lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <1236245899-6706-1-git-send-email-donari75@gmail.com>
Date:	Thu,  5 Mar 2009 18:38:19 +0900
From:	unsik Kim <donari75@...il.com>
To:	akpm@...ux-foundation.org
Cc:	linux-kernel@...r.kernel.org, hch@...radead.org,
	alan@...rguk.ukuu.org.uk, shdl@...alwe.fi,
	harvey.harrison@...il.com, minchan.kim@...il.com,
	unsik Kim <donari75@...il.com>
Subject: [PATCH] mflash: reflect akpm's review

* 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 <donari75@...il.com>
---
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 <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
+#include <linux/libata.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
@@ -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 <linux/blkdev.h>
-#include <linux/hdreg.h>
+#include <linux/ata.h>
 
 /* 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@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ