Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755287AbZCEJjS (ORCPT ); Thu, 5 Mar 2009 04:39:18 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753369AbZCEJjE (ORCPT ); Thu, 5 Mar 2009 04:39:04 -0500 Received: from rv-out-0506.google.com ([209.85.198.226]:60827 "EHLO rv-out-0506.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751524AbZCEJjA (ORCPT ); Thu, 5 Mar 2009 04:39:00 -0500 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=H7jWbmaaH7CF+ToGS5sUTcoqnnN0Bnv4/KkGacRgLlC/nLkvMVVjb6/o20gonTUbMp MkM9gRcu/xsONgtLHGvX1+ozwtmKXuArKVHKPBqYZGLV4zQmoqa/YEwGpNCt8wqiDBDa PbOA1JpUi12/cm0ndRhv8DwxMVfKZJnQBgrXc= From: unsik Kim To: akpm@linux-foundation.org Cc: linux-kernel@vger.kernel.org, hch@infradead.org, alan@lxorguk.ukuu.org.uk, shdl@zakalwe.fi, harvey.harrison@gmail.com, minchan.kim@gmail.com, unsik Kim Subject: [PATCH] mflash: reflect akpm's review Date: Thu, 5 Mar 2009 18:38:19 +0900 Message-Id: <1236245899-6706-1-git-send-email-donari75@gmail.com> X-Mailer: git-send-email 1.5.6.6 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 27442 Lines: 909 * refine and reduce mg_wait's timeout value * reduce probing time: add dev_attr field to mg_drv_data and reset-out GPIO resource * remove uneffective reset when error occured * remove pointless "?" * use correct jiffy wrap * replace local mg_ide_fixstring to libata_core's * avoid divide-by-zero * change host->dev_base type to 'void __iomem *' * add missing GPIOLIB and ATA dependency Signed-off-by: unsik Kim --- When using interrupt mode, most of the busy wait eliminated. The worst case of busy wait is under 10msec. (This is extremely rare case) Typically wait <500nsec at mg_out's mg_wait. --- Documentation/blockdev/mflash.txt | 13 ++- drivers/block/Kconfig | 2 +- drivers/block/mg_disk.c | 352 ++++++++++++++++++++----------------- include/linux/mg_disk.h | 57 +++++-- 4 files changed, 246 insertions(+), 178 deletions(-) diff --git a/Documentation/blockdev/mflash.txt b/Documentation/blockdev/mflash.txt index d7522eb..1f610ec 100644 --- a/Documentation/blockdev/mflash.txt +++ b/Documentation/blockdev/mflash.txt @@ -36,6 +36,8 @@ configuration file is all. Here is some pseudo example. static struct mg_drv_data mflash_drv_data = { /* If you want to polling driver set to 1 */ .use_polling = 0, + /* device attribution */ + .dev_attr = MG_BOOT_DEV }; static struct resource mg_mflash_rsc[] = { @@ -55,9 +57,18 @@ static struct resource mg_mflash_rsc[] = { [2] = { .start = 43, .end = 43, - .name = "mg_rst", + .name = MG_RST_PIN, .flags = IORESOURCE_IO }, + /* mflash reset-out pin + * If you use mflash as storage device (i.e. other than MG_BOOT_DEV), + * should assign this */ + [3] = { + .start = 51, + .end = 51, + .name = MG_RSTOUT_PIN, + .flags = IORESOURCE_IO + } }; static struct platform_device mflash_dev = { diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 88ad8e7..8d32823 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -405,7 +405,7 @@ config ATA_OVER_ETH config MG_DISK tristate "mGine mflash, gflash support" - depends on ARM + depends on ARM && ATA && GPIOLIB help mGine mFlash(gFlash) block device driver diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 10ac8d6..fb39d9a 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,7 @@ static void mg_request(struct request_queue *); static void mg_dump_status(const char *msg, unsigned int stat, struct mg_host *host) { - char *name = MG_DISK_NAME"?"; + char *name = MG_DISK_NAME; struct request *req; if (host->breq) { @@ -39,7 +40,7 @@ static void mg_dump_status(const char *msg, unsigned int stat, name = req->rq_disk->disk_name; } - printk(KERN_DEBUG "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); + printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff); if (stat & MG_REG_STATUS_BIT_BUSY) printk("Busy "); if (stat & MG_REG_STATUS_BIT_READY) @@ -58,8 +59,8 @@ static void mg_dump_status(const char *msg, unsigned int stat, if ((stat & MG_REG_STATUS_BIT_ERROR) == 0) { host->error = 0; } else { - host->error = inb(host->dev_base + MG_REG_ERROR); - printk(KERN_DEBUG "%s: %s: error=0x%02x { ", name, msg, + host->error = inb((unsigned long)host->dev_base + MG_REG_ERROR); + printk(KERN_ERR "%s: %s: error=0x%02x { ", name, msg, host->error & 0xff); if (host->error & MG_REG_ERR_BBK) printk("BadSector "); @@ -89,14 +90,16 @@ static void mg_dump_status(const char *msg, unsigned int stat, static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) { u8 status; - u64 expire, cur_jiffies; + unsigned long expire, cur_jiffies; + struct mg_drv_data *prv_data = host->dev->platform_data; host->error = MG_ERR_NONE; - expire = get_jiffies_64() + msecs_to_jiffies(msec); + expire = jiffies + msecs_to_jiffies(msec); + + status = inb((unsigned long)host->dev_base + MG_REG_STATUS); - status = inb(host->dev_base + MG_REG_STATUS); do { - cur_jiffies = get_jiffies_64(); + cur_jiffies = jiffies; if (status & MG_REG_STATUS_BIT_BUSY) { if (expect == MG_REG_STATUS_BIT_BUSY) break; @@ -115,18 +118,39 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) if (status & MG_REG_STATUS_BIT_DATA_REQ) break; } - status = inb(host->dev_base + MG_REG_STATUS); - } while (cur_jiffies < expire); + if (!msec) { + mg_dump_status("not ready", status, host); + return MG_ERR_INV_STAT; + } + if (prv_data->use_polling) + msleep(1); + + status = inb((unsigned long)host->dev_base + MG_REG_STATUS); + } while (time_before(cur_jiffies, expire)); - if (cur_jiffies >= expire) + if (time_after_eq(cur_jiffies, expire) && msec) host->error = MG_ERR_TIMEOUT; return host->error; } +static unsigned int mg_wait_rstout(u32 rstout, u32 msec) +{ + unsigned long expire; + + expire = jiffies + msecs_to_jiffies(msec); + while (time_before(jiffies, expire)) { + if (gpio_get_value(rstout) == 1) + return MG_ERR_NONE; + msleep(10); + } + + return MG_ERR_RSTOUT; +} + static void mg_unexpected_intr(struct mg_host *host) { - u32 status = inb(host->dev_base + MG_REG_STATUS); + u32 status = inb((unsigned long)host->dev_base + MG_REG_STATUS); mg_dump_status("mg_unexpected_intr", status, host); } @@ -144,84 +168,64 @@ static irqreturn_t mg_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static void mg_ide_fixstring(u8 *s, const int bytecount) -{ - u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */ - - /* convert from big-endian to host byte order */ - for (p = s ; p != end ; p += 2) - be16_to_cpus((u16 *) p); - - /* strip leading blanks */ - p = s; - while (s != end && *s == ' ') - ++s; - /* compress internal blanks and strip trailing blanks */ - while (s != end && *s) { - if (*s++ != ' ' || (s != end && *s && *s != ' ')) - *p++ = *(s-1); - } - /* wipe out trailing garbage */ - while (p != end) - *p++ = '\0'; -} - static int mg_get_disk_id(struct mg_host *host) { - u32 i, res; + u32 i; s32 err; - u16 *id = (u16 *)&host->id_data; + const u16 *id = host->id; struct mg_drv_data *prv_data = host->dev->platform_data; + char fwrev[ATA_ID_FW_REV_LEN + 1]; + char model[ATA_ID_PROD_LEN + 1]; + char serial[ATA_ID_SERNO_LEN + 1]; if (!prv_data->use_polling) outb(MG_REG_CTRL_INTR_DISABLE, - host->dev_base + MG_REG_DRV_CTRL); + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); - outb(MG_CMD_ID, host->dev_base + MG_REG_COMMAND); - err = mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, 3000); + outb(MG_CMD_ID, (unsigned long)host->dev_base + MG_REG_COMMAND); + err = mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_RD_DRQ); if (err) return err; for (i = 0; i < (MG_SECTOR_SIZE >> 1); i++) - id[i] = le16_to_cpu(inw(host->dev_base + MG_BUFF_OFFSET + - i * 2)); + host->id[i] = le16_to_cpu(inw((unsigned long)host->dev_base + + MG_BUFF_OFFSET + i * 2)); - outb(MG_CMD_RD_CONF, host->dev_base + MG_REG_COMMAND); - err = mg_wait(host, MG_STAT_READY, 3000); + outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); + err = mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD); if (err) return err; - if ((host->id_data.field_valid & 1) == 0) + if ((id[ATA_ID_FIELD_VALID] & 1) == 0) return MG_ERR_TRANSLATION; -#ifdef __BIG_ENDIAN - host->id_data.lba_capacity = (host->id_data.lba_capacity << 16) - | (host->id_data.lba_capacity >> 16); -#endif /* __BIG_ENDIAN */ - if (MG_RES_SEC) { - /* modify cyls, lba_capacity */ - host->id_data.cyls = (host->id_data.lba_capacity - MG_RES_SEC) / - host->id_data.heads / host->id_data.sectors; - res = host->id_data.lba_capacity - host->id_data.cyls * - host->id_data.heads * host->id_data.sectors; - host->id_data.lba_capacity -= res; - } - host->tot_sectors = host->id_data.lba_capacity; - mg_ide_fixstring(host->id_data.model, - sizeof(host->id_data.model)); - mg_ide_fixstring(host->id_data.serial_no, - sizeof(host->id_data.serial_no)); - mg_ide_fixstring(host->id_data.fw_rev, - sizeof(host->id_data.fw_rev)); - printk(KERN_INFO "mg_disk: model: %s\n", host->id_data.model); - printk(KERN_INFO "mg_disk: firm: %.8s\n", host->id_data.fw_rev); - printk(KERN_INFO "mg_disk: serial: %s\n", - host->id_data.serial_no); + host->n_sectors = ata_id_u32(id, ATA_ID_LBA_CAPACITY); + host->cyls = id[ATA_ID_CYLS]; + host->heads = id[ATA_ID_HEADS]; + host->sectors = id[ATA_ID_SECTORS]; + + if (MG_RES_SEC && host->heads && host->sectors) { + /* modify cyls, n_sectors */ + host->cyls = (host->n_sectors - MG_RES_SEC) / + host->heads / host->sectors; + host->nres_sectors = host->n_sectors - host->cyls * + host->heads * host->sectors; + host->n_sectors -= host->nres_sectors; + } + + ata_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev)); + ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + printk(KERN_INFO "mg_disk: model: %s\n", model); + printk(KERN_INFO "mg_disk: firm: %.8s\n", fwrev); + printk(KERN_INFO "mg_disk: serial: %s\n", serial); printk(KERN_INFO "mg_disk: %d + reserved %d sectors\n", - host->tot_sectors, res); + host->n_sectors, host->nres_sectors); if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, host->dev_base + MG_REG_DRV_CTRL); + outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); return err; } @@ -235,13 +239,13 @@ static int mg_disk_init(struct mg_host *host) /* hdd rst low */ gpio_set_value(host->rst, 0); - err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, 300); + err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); if (err) return err; /* hdd rst high */ gpio_set_value(host->rst, 1); - err = mg_wait(host, MG_STAT_READY, 3000); + err = mg_wait(host, MG_STAT_READY, MG_TMAX_HDRST_TO_RDY); if (err) return err; @@ -249,20 +253,20 @@ static int mg_disk_init(struct mg_host *host) outb(MG_REG_CTRL_RESET | (prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : MG_REG_CTRL_INTR_ENABLE), - host->dev_base + MG_REG_DRV_CTRL); - err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, 3000); + (unsigned long)host->dev_base + MG_REG_DRV_CTRL); + err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY); if (err) return err; /* soft reset off */ outb(prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE : MG_REG_CTRL_INTR_ENABLE, - host->dev_base + MG_REG_DRV_CTRL); - err = mg_wait(host, MG_STAT_READY, 3000); + (unsigned long)host->dev_base + MG_REG_DRV_CTRL); + err = mg_wait(host, MG_STAT_READY, MG_TMAX_SWRST_TO_RDY); if (err) return err; - init_status = inb(host->dev_base + MG_REG_STATUS) & 0xf; + init_status = inb((unsigned long)host->dev_base + MG_REG_STATUS) & 0xf; if (init_status == 0xf) return MG_ERR_INIT_STAT; @@ -273,15 +277,10 @@ static int mg_disk_init(struct mg_host *host) static void mg_bad_rw_intr(struct mg_host *host) { struct request *req = elv_next_request(host->breq); - if (req != NULL) { - if (++req->errors >= MG_MAX_ERRORS) { + if (req != NULL) + if (++req->errors >= MG_MAX_ERRORS || + host->error == MG_ERR_TIMEOUT) end_request(req, 0); - } else if (req->errors % MG_RESET_FREQ == 0 || - host->error == MG_ERR_TIMEOUT) { - host->reset = 1; - } - /* Otherwise just retry */ - } } static unsigned int mg_out(struct mg_host *host, @@ -292,7 +291,7 @@ static unsigned int mg_out(struct mg_host *host, { struct mg_drv_data *prv_data = host->dev->platform_data; - if (mg_wait(host, MG_STAT_READY, 3000)) + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) return host->error; if (!prv_data->use_polling) { @@ -301,13 +300,15 @@ static unsigned int mg_out(struct mg_host *host, } if (MG_RES_SEC) sect_num += MG_RES_SEC; - outb((u8)sect_cnt, host->dev_base + MG_REG_SECT_CNT); - outb((u8)sect_num, host->dev_base + MG_REG_SECT_NUM); - outb((u8)(sect_num >> 8), host->dev_base + MG_REG_CYL_LOW); - outb((u8)(sect_num >> 16), host->dev_base + MG_REG_CYL_HIGH); + outb((u8)sect_cnt, (unsigned long)host->dev_base + MG_REG_SECT_CNT); + outb((u8)sect_num, (unsigned long)host->dev_base + MG_REG_SECT_NUM); + outb((u8)(sect_num >> 8), (unsigned long)host->dev_base + + MG_REG_CYL_LOW); + outb((u8)(sect_num >> 16), (unsigned long)host->dev_base + + MG_REG_CYL_HIGH); outb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE), - host->dev_base + MG_REG_DRV_HEAD); - outb(cmd, host->dev_base + MG_REG_COMMAND); + (unsigned long)host->dev_base + MG_REG_DRV_HEAD); + outb(cmd, (unsigned long)host->dev_base + MG_REG_COMMAND); return MG_ERR_NONE; } @@ -318,14 +319,6 @@ static void mg_read(struct request *req) remains = req->nr_sectors; - if (host->reset) { - if (mg_disk_init(host)) { - end_request(req, 0); - return; - } - host->reset = 0; - } - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, 0) != MG_ERR_NONE) mg_bad_rw_intr(host); @@ -334,14 +327,15 @@ static void mg_read(struct request *req) remains, req->sector, req->buffer); while (remains) { - if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, 3000) != - MG_ERR_NONE) { + if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, + MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { *(u16 *)req->buffer = - inw(host->dev_base + MG_BUFF_OFFSET + (j << 1)); + inw((unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); req->buffer += 2; } @@ -357,7 +351,8 @@ static void mg_read(struct request *req) req = elv_next_request(host->breq); } - outb(MG_CMD_RD_CONF, host->dev_base + MG_REG_COMMAND); + outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + + MG_REG_COMMAND); } } @@ -368,14 +363,6 @@ static void mg_write(struct request *req) remains = req->nr_sectors; - if (host->reset) { - if (mg_disk_init(host)) { - end_request(req, 0); - return; - } - host->reset = 0; - } - if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, 0) != MG_ERR_NONE) { mg_bad_rw_intr(host); @@ -386,13 +373,14 @@ static void mg_write(struct request *req) MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", remains, req->sector, req->buffer); while (remains) { - if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, 3000) != - MG_ERR_NONE) { + if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, + MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { mg_bad_rw_intr(host); return; } for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) { - outw(*(u16 *)req->buffer, host->dev_base + + outw(*(u16 *)req->buffer, + (unsigned long)host->dev_base + MG_BUFF_OFFSET + (j << 1)); req->buffer += 2; } @@ -407,7 +395,8 @@ static void mg_write(struct request *req) req = elv_next_request(host->breq); } - outb(MG_CMD_WR_CONF, host->dev_base + MG_REG_COMMAND); + outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + + MG_REG_COMMAND); } } @@ -418,7 +407,7 @@ static void mg_read_intr(struct mg_host *host) /* check status */ do { - i = inb(host->dev_base + MG_REG_STATUS); + i = inb((unsigned long)host->dev_base + MG_REG_STATUS); if (i & MG_REG_STATUS_BIT_BUSY) break; if (!MG_READY_OK(i)) @@ -438,7 +427,8 @@ ok_to_read: /* read 1 sector */ for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { *(u16 *)req->buffer = - inw(host->dev_base + MG_BUFF_OFFSET + (i << 1)); + inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + + (i << 1)); req->buffer += 2; } @@ -462,7 +452,7 @@ ok_to_read: } /* send read confirm */ - outb(MG_CMD_RD_CONF, host->dev_base + MG_REG_COMMAND); + outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); /* goto next request */ if (!i) @@ -480,7 +470,7 @@ static void mg_write_intr(struct mg_host *host) /* check status */ do { - i = inb(host->dev_base + MG_REG_STATUS); + i = inb((unsigned long)host->dev_base + MG_REG_STATUS); if (i & MG_REG_STATUS_BIT_BUSY) break; if (!MG_READY_OK(i)) @@ -508,7 +498,8 @@ ok_to_write: if (i > 0) { buff = (u16 *)req->buffer; for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { - outw(*buff, host->dev_base + MG_BUFF_OFFSET + (j << 1)); + outw(*buff, (unsigned long)host->dev_base + + MG_BUFF_OFFSET + (j << 1)); buff++; } MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", @@ -518,7 +509,7 @@ ok_to_write: } /* send write confirm */ - outb(MG_CMD_WR_CONF, host->dev_base + MG_REG_COMMAND); + outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); if (!i) mg_request(host->breq); @@ -589,26 +580,30 @@ static unsigned int mg_issue_req(struct request *req, case WRITE: /* TODO : handler */ outb(MG_REG_CTRL_INTR_DISABLE, - host->dev_base + MG_REG_DRV_CTRL); + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr) != MG_ERR_NONE) { mg_bad_rw_intr(host); return host->error; } del_timer(&host->timer); - mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, 3000); - outb(MG_REG_CTRL_INTR_ENABLE, host->dev_base + MG_REG_DRV_CTRL); + mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_WR_DRQ); + outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); if (host->error) { mg_bad_rw_intr(host); return host->error; } buff = (u16 *)req->buffer; for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { - outw(*buff, host->dev_base + MG_BUFF_OFFSET + (i << 1)); + outw(*buff, (unsigned long)host->dev_base + + MG_BUFF_OFFSET + (i << 1)); buff++; } mod_timer(&host->timer, jiffies + 3 * HZ); - outb(MG_CMD_WR_CONF, host->dev_base + MG_REG_COMMAND); + outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + + MG_REG_COMMAND); break; default: printk(KERN_WARNING "%s:%d unknown command\n", @@ -639,14 +634,6 @@ static void mg_request(struct request_queue *q) del_timer(&host->timer); - if (host->reset) { - if (mg_disk_init(host)) { - end_request(req, 0); - return; - } - host->reset = 0; - } - sect_num = req->sector; /* deal whole segments */ sect_cnt = req->nr_sectors; @@ -675,9 +662,9 @@ static int mg_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct mg_host *host = bdev->bd_disk->private_data; - geo->cylinders = host->id_data.cyls; - geo->heads = host->id_data.heads; - geo->sectors = host->id_data.sectors; + geo->cylinders = (unsigned short)host->cyls; + geo->heads = (unsigned char)host->heads; + geo->sectors = (unsigned char)host->sectors; return 0; } @@ -690,20 +677,23 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state) struct mg_drv_data *prv_data = plat_dev->dev.platform_data; struct mg_host *host = prv_data->host; - if (mg_wait(host, MG_STAT_READY, 3000)) + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) return -EIO; if (!prv_data->use_polling) outb(MG_REG_CTRL_INTR_DISABLE, - host->dev_base + MG_REG_DRV_CTRL); + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); - outb(MG_CMD_SLEEP, host->dev_base + MG_REG_COMMAND); - mdelay(1); + outb(MG_CMD_SLEEP, (unsigned long)host->dev_base + MG_REG_COMMAND); + /* wait until mflash deep sleep */ + msleep(1); - if (mg_wait(host, MG_STAT_READY, 3000)) { + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) { if (!prv_data->use_polling) outb(MG_REG_CTRL_INTR_ENABLE, - host->dev_base + MG_REG_DRV_CTRL); + (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); return -EIO; } @@ -715,17 +705,19 @@ static int mg_resume(struct platform_device *plat_dev) struct mg_drv_data *prv_data = plat_dev->dev.platform_data; struct mg_host *host = prv_data->host; - if (mg_wait(host, MG_STAT_READY, 3000)) + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) return -EIO; - outb(MG_CMD_WAKEUP, host->dev_base + MG_REG_COMMAND); - mdelay(1); + outb(MG_CMD_WAKEUP, (unsigned long)host->dev_base + MG_REG_COMMAND); + /* wait until mflash wakeup */ + msleep(1); - if (mg_wait(host, MG_STAT_READY, 3000)) + if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) return -EIO; if (!prv_data->use_polling) - outb(MG_REG_CTRL_INTR_ENABLE, host->dev_base + MG_REG_DRV_CTRL); + outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base + + MG_REG_DRV_CTRL); return 0; } @@ -745,14 +737,13 @@ static int mg_probe(struct platform_device *plat_dev) } /* alloc mg_host */ - host = kmalloc(sizeof(struct mg_host), GFP_KERNEL); + host = kzalloc(sizeof(struct mg_host), GFP_KERNEL); if (!host) { printk(KERN_ERR "%s:%d fail (no memory for mg_host)\n", __func__, __LINE__); err = -ENOMEM; goto probe_err; } - memset(host, 0, sizeof(struct mg_host)); host->major = MG_DISK_MAJ; /* link each other */ @@ -767,7 +758,7 @@ static int mg_probe(struct platform_device *plat_dev) err = -EINVAL; goto probe_err_2; } - host->dev_base = (unsigned long)ioremap(rsc->start , rsc->end + 1); + host->dev_base = ioremap(rsc->start , rsc->end + 1); if (!host->dev_base) { printk(KERN_ERR "%s:%d ioremap fail\n", __func__, __LINE__); @@ -777,7 +768,8 @@ static int mg_probe(struct platform_device *plat_dev) MG_DBG("dev_base = 0x%x\n", (u32)host->dev_base); /* get reset pin */ - rsc = platform_get_resource(plat_dev, IORESOURCE_IO, 0); + rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO, + MG_RST_PIN); if (!rsc) { printk(KERN_ERR "%s:%d get reset pin fail\n", __func__, __LINE__); @@ -787,18 +779,44 @@ static int mg_probe(struct platform_device *plat_dev) host->rst = rsc->start; /* init rst pin */ - err = gpio_request(host->rst, "mg_rst"); + err = gpio_request(host->rst, MG_RST_PIN); if (err) goto probe_err_3; gpio_direction_output(host->rst, 1); - /* disk init */ - err = mg_disk_init(host); - if (err) { - printk(KERN_ERR "%s:%d fail (err code : %d)\n", - __func__, __LINE__, err); - err = -EIO; + /* reset out pin */ + if (!(prv_data->dev_attr & MG_DEV_MASK)) goto probe_err_3a; + + if (prv_data->dev_attr != MG_BOOT_DEV) { + rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO, + MG_RSTOUT_PIN); + if (!rsc) { + printk(KERN_ERR "%s:%d get reset-out pin fail\n", + __func__, __LINE__); + err = -EIO; + goto probe_err_3a; + } + host->rstout = rsc->start; + err = gpio_request(host->rstout, MG_RSTOUT_PIN); + if (err) + goto probe_err_3a; + gpio_direction_input(host->rstout); + } + + /* disk reset */ + if (prv_data->dev_attr == MG_STORAGE_DEV) { + /* If POR seq. not yet finised, wait */ + err = mg_wait_rstout(host->rstout, MG_TMAX_RSTOUT); + if (err) + goto probe_err_3b; + err = mg_disk_init(host); + if (err) { + printk(KERN_ERR "%s:%d fail (err code : %d)\n", + __func__, __LINE__, err); + err = -EIO; + goto probe_err_3b; + } } /* get irq resource */ @@ -806,7 +824,7 @@ static int mg_probe(struct platform_device *plat_dev) host->irq = platform_get_irq(plat_dev, 0); if (host->irq == -ENXIO) { err = host->irq; - goto probe_err_3a; + goto probe_err_3b; } err = request_irq(host->irq, mg_irq, IRQF_DISABLED | IRQF_TRIGGER_RISING, @@ -814,7 +832,7 @@ static int mg_probe(struct platform_device *plat_dev) if (err) { printk(KERN_ERR "%s:%d fail (request_irq err=%d)\n", __func__, __LINE__, err); - goto probe_err_3a; + goto probe_err_3b; } } @@ -880,7 +898,7 @@ static int mg_probe(struct platform_device *plat_dev) host->gd->private_data = host; sprintf(host->gd->disk_name, MG_DISK_NAME"a"); - set_capacity(host->gd, host->tot_sectors); + set_capacity(host->gd, host->n_sectors); add_disk(host->gd); @@ -895,10 +913,12 @@ probe_err_5: probe_err_4: if (!prv_data->use_polling) free_irq(host->irq, host); +probe_err_3b: + gpio_free(host->rstout); probe_err_3a: gpio_free(host->rst); probe_err_3: - iounmap((void __iomem *)host->dev_base); + iounmap(host->dev_base); probe_err_2: kfree(host); probe_err: @@ -930,13 +950,17 @@ static int mg_remove(struct platform_device *plat_dev) if (!prv_data->use_polling) free_irq(host->irq, host); + /* free reset-out pin */ + if (prv_data->dev_attr != MG_BOOT_DEV) + gpio_free(host->rstout); + /* free rst pin */ if (host->rst) gpio_free(host->rst); /* unmap io */ if (host->dev_base) - iounmap((void __iomem *)host->dev_base); + iounmap(host->dev_base); /* free mg_host */ kfree(host); diff --git a/include/linux/mg_disk.h b/include/linux/mg_disk.h index 4f1a4a2..1f76b1e 100644 --- a/include/linux/mg_disk.h +++ b/include/linux/mg_disk.h @@ -16,7 +16,7 @@ #define __MG_DISK_H__ #include -#include +#include /* name for block device */ #define MG_DISK_NAME "mgd" @@ -91,14 +91,15 @@ #define MG_REG_ERR_BBK 0x80 /* error code for others */ -#define MG_ERR_NONE 0 -#define MG_ERR_TIMEOUT 0x100 -#define MG_ERR_INIT_STAT 0x101 -#define MG_ERR_TRANSLATION 0x102 -#define MG_ERR_CTRL_RST 0x103 +#define MG_ERR_NONE 0 +#define MG_ERR_TIMEOUT 0x100 +#define MG_ERR_INIT_STAT 0x101 +#define MG_ERR_TRANSLATION 0x102 +#define MG_ERR_CTRL_RST 0x103 +#define MG_ERR_INV_STAT 0x104 +#define MG_ERR_RSTOUT 0x105 -#define MG_MAX_ERRORS 16 /* Max read/write errors/sector */ -#define MG_RESET_FREQ 4 /* Reset controller every 4th retry */ +#define MG_MAX_ERRORS 6 /* Max read/write errors */ /* command */ #define MG_CMD_RD 0x20 @@ -127,11 +128,38 @@ #define MG_BURST_LEN_32 (4 << 1) #define MG_BURST_LEN_CONT (0 << 1) +/* timeout value (unit: ms) */ +#define MG_TMAX_CONF_TO_CMD 1 +#define MG_TMAX_WAIT_RD_DRQ 10 +#define MG_TMAX_WAIT_WR_DRQ 500 +#define MG_TMAX_RST_TO_BUSY 10 +#define MG_TMAX_HDRST_TO_RDY 500 +#define MG_TMAX_SWRST_TO_RDY 500 +#define MG_TMAX_RSTOUT 3000 + +/* device attribution */ +/* use mflash as boot device */ +#define MG_BOOT_DEV (1 << 0) +/* use mflash as storage device */ +#define MG_STORAGE_DEV (1 << 1) +/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */ +#define MG_STORAGE_DEV_SKIP_RST (1 << 2) + +#define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST) + +/* names of GPIO resource */ +#define MG_RST_PIN "mg_rst" +/* except MG_BOOT_DEV, reset-out pin should be assigned */ +#define MG_RSTOUT_PIN "mg_rstout" + /* private driver data */ struct mg_drv_data { /* disk resource */ u32 use_polling; + /* device attribution */ + u32 dev_attr; + /* internally used */ struct mg_host *host; }; @@ -147,16 +175,21 @@ struct mg_host { struct timer_list timer; void (*mg_do_intr) (struct mg_host *); - struct hd_driveid id_data; - u32 tot_sectors; + u16 id[ATA_ID_WORDS]; + + u16 cyls; + u16 heads; + u16 sectors; + u32 n_sectors; + u32 nres_sectors; - unsigned long dev_base; + void __iomem *dev_base; unsigned int irq; unsigned int rst; + unsigned int rstout; u32 major; u32 error; - u32 reset; }; /* -- 1.5.6.6 Regards, unsik Kim -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/