All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/29] My patch queue for memorystick subsystem
@ 2010-10-22 23:53 Maxim Levitsky
  2010-10-22 23:53 ` [PATCH 01/29] memstick: core: header cleanups Maxim Levitsky
                   ` (29 more replies)
  0 siblings, 30 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

Hi,

As requested, this is split up series of the work I did for the
memorystick subsystem.

All patches compile tested.
All patches except jmicron patches also run tested on my r592
The end result of jmicron patches is exactly the same as my old patch
that did work very well. I will test the patches tommorow though to ensure that
all of them work for bisectability.

Please review & merge.

Best regards,
	Maxim Levitsky



^ permalink raw reply	[flat|nested] 84+ messages in thread

* [PATCH 01/29] memstick: core: header cleanups
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 14:44   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code Maxim Levitsky
                   ` (28 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky, Maxim Levitsky

* Replace the __attribute__((packed)) with __packed
* Add struct mspro_cmdex_argument, argument for MS_TPC_EX_SET_CMD
* Increase size of inline buffer in memstick_request to 32
because thats the size of registers and someone might need to read them
all. That structure is allocated one per memstick host, so its size
doesn't matter.

* Add comments about few members of memstick_request

Signed-off-by: Maxim Levitsky <maximlevitky@gmail.com>
---
 include/linux/memstick.h |   50 ++++++++++++++++++++++++++++++++++-----------
 1 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/include/linux/memstick.h b/include/linux/memstick.h
index 690c35a..5479f7d 100644
--- a/include/linux/memstick.h
+++ b/include/linux/memstick.h
@@ -45,14 +45,14 @@ struct ms_status_register {
 #define MEMSTICK_STATUS1_DTER 0x20
 #define MEMSTICK_STATUS1_FB1  0x40
 #define MEMSTICK_STATUS1_MB   0x80
-} __attribute__((packed));
+} __packed;
 
 struct ms_id_register {
 	unsigned char type;
 	unsigned char if_mode;
 	unsigned char category;
 	unsigned char class;
-} __attribute__((packed));
+} __packed;
 
 struct ms_param_register {
 	unsigned char system;
@@ -68,7 +68,7 @@ struct ms_param_register {
 #define MEMSTICK_CP_OVERWRITE 0x80
 
 	unsigned char page_address;
-} __attribute__((packed));
+} __packed;
 
 struct ms_extra_data_register {
 	unsigned char  overwrite_flag;
@@ -84,7 +84,7 @@ struct ms_extra_data_register {
 #define MEMSTICK_MANAGEMENT_SCMS0  0x20
 
 	unsigned short logical_address;
-} __attribute__((packed));
+} __packed;
 
 struct ms_register {
 	struct ms_status_register     status;
@@ -92,7 +92,7 @@ struct ms_register {
 	unsigned char                 reserved[8];
 	struct ms_param_register      param;
 	struct ms_extra_data_register extra_data;
-} __attribute__((packed));
+} __packed;
 
 struct mspro_param_register {
 	unsigned char  system;
@@ -103,7 +103,7 @@ struct mspro_param_register {
 	__be16 data_count;
 	__be32 data_address;
 	unsigned char  tpc_param;
-} __attribute__((packed));
+} __packed;
 
 struct mspro_io_info_register {
 	unsigned char version;
@@ -111,20 +111,28 @@ struct mspro_io_info_register {
 	unsigned char current_req;
 	unsigned char card_opt_info;
 	unsigned char rdy_wait_time;
-} __attribute__((packed));
+} __packed;
 
 struct mspro_io_func_register {
 	unsigned char func_enable;
 	unsigned char func_select;
 	unsigned char func_intmask;
 	unsigned char transfer_mode;
-} __attribute__((packed));
+} __packed;
 
 struct mspro_io_cmd_register {
 	unsigned short tpc_param;
 	unsigned short data_count;
 	unsigned int   data_address;
-} __attribute__((packed));
+} __packed;
+
+
+struct mspro_cmdex_argument {
+	unsigned char  command;
+	__be16 data_count;
+	__be32 data_address;
+} __packed;
+
 
 struct mspro_register {
 	struct ms_status_register     status;
@@ -138,14 +146,14 @@ struct mspro_register {
 	struct mspro_io_cmd_register  io_cmd;
 	unsigned char                 io_int;
 	unsigned char                 io_int_func;
-} __attribute__((packed));
+} __packed;
 
 struct ms_register_addr {
 	unsigned char r_offset;
 	unsigned char r_length;
 	unsigned char w_offset;
 	unsigned char w_length;
-} __attribute__((packed));
+} __packed;
 
 enum memstick_tpc {
 	MS_TPC_READ_MG_STATUS   = 0x01,
@@ -236,6 +244,24 @@ struct memstick_device_id {
 #define MEMSTICK_CLASS_WP             0x03
 };
 
+/* IO request that host driver gets from memtick core
+ *
+ * Note about the 'need_card_int' flag:
+
+ * In serial mode that flag _hints_ the host driver to wait till card
+ * raises the INT signal, so that core could spare sending redundant
+ * MS_TPC_GET_INT requests.
+ *
+ * In _parallel_ mode, that flag must be honored,
+ * and besides waiting, the host driver must read the INT register
+ * (via data lines)
+ *
+ * In addition to that if hardware is 'smart', and is able to read
+ * the INT register even in serial mode by sending MS_TPC_GET_INT
+ * by itself (This capablility is indicated by host via
+ * MEMSTICK_CAP_AUTO_GET_INT),
+ * then the serial mode behavier must match the parallel.
+ */
 struct memstick_request {
 	unsigned char tpc;
 	unsigned char data_dir:1,
@@ -247,7 +273,7 @@ struct memstick_request {
 		struct scatterlist sg;
 		struct {
 			unsigned char data_len;
-			unsigned char data[15];
+			unsigned char data[32];
 		};
 	};
 };
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code.
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
  2010-10-22 23:53 ` [PATCH 01/29] memstick: core: header cleanups Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 14:50   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 03/29] memstick: core: add new functions Maxim Levitsky
                   ` (27 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/memstick.c |  293 ++++++++++++++++++++------------------
 include/linux/memstick.h         |   44 ++++---
 2 files changed, 184 insertions(+), 153 deletions(-)

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index c00fe82..5a501a4 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -202,119 +202,6 @@ static int memstick_dummy_check(struct memstick_dev *card)
 	return 0;
 }
 
-/**
- * memstick_detect_change - schedule media detection on memstick host
- * @host - host to use
- */
-void memstick_detect_change(struct memstick_host *host)
-{
-	queue_work(workqueue, &host->media_checker);
-}
-EXPORT_SYMBOL(memstick_detect_change);
-
-/**
- * memstick_next_req - called by host driver to obtain next request to process
- * @host - host to use
- * @mrq - pointer to stick the request to
- *
- * Host calls this function from idle state (*mrq == NULL) or after finishing
- * previous request (*mrq should point to it). If previous request was
- * unsuccessful, it is retried for predetermined number of times. Return value
- * of 0 means that new request was assigned to the host.
- */
-int memstick_next_req(struct memstick_host *host, struct memstick_request **mrq)
-{
-	int rc = -ENXIO;
-
-	if ((*mrq) && (*mrq)->error && host->retries) {
-		(*mrq)->error = rc;
-		host->retries--;
-		return 0;
-	}
-
-	if (host->card && host->card->next_request)
-		rc = host->card->next_request(host->card, mrq);
-
-	if (!rc)
-		host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1;
-	else
-		*mrq = NULL;
-
-	return rc;
-}
-EXPORT_SYMBOL(memstick_next_req);
-
-/**
- * memstick_new_req - notify the host that some requests are pending
- * @host - host to use
- */
-void memstick_new_req(struct memstick_host *host)
-{
-	if (host->card) {
-		host->retries = cmd_retries;
-		INIT_COMPLETION(host->card->mrq_complete);
-		host->request(host);
-	}
-}
-EXPORT_SYMBOL(memstick_new_req);
-
-/**
- * memstick_init_req_sg - set request fields needed for bulk data transfer
- * @mrq - request to use
- * @tpc - memstick Transport Protocol Command
- * @sg - TPC argument
- */
-void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
-			  const struct scatterlist *sg)
-{
-	mrq->tpc = tpc;
-	if (tpc & 8)
-		mrq->data_dir = WRITE;
-	else
-		mrq->data_dir = READ;
-
-	mrq->sg = *sg;
-	mrq->long_data = 1;
-
-	if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD)
-		mrq->need_card_int = 1;
-	else
-		mrq->need_card_int = 0;
-}
-EXPORT_SYMBOL(memstick_init_req_sg);
-
-/**
- * memstick_init_req - set request fields needed for short data transfer
- * @mrq - request to use
- * @tpc - memstick Transport Protocol Command
- * @buf - TPC argument buffer
- * @length - TPC argument size
- *
- * The intended use of this function (transfer of data items several bytes
- * in size) allows us to just copy the value between request structure and
- * user supplied buffer.
- */
-void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
-		       const void *buf, size_t length)
-{
-	mrq->tpc = tpc;
-	if (tpc & 8)
-		mrq->data_dir = WRITE;
-	else
-		mrq->data_dir = READ;
-
-	mrq->data_len = length > sizeof(mrq->data) ? sizeof(mrq->data) : length;
-	if (mrq->data_dir == WRITE)
-		memcpy(mrq->data, buf, mrq->data_len);
-
-	mrq->long_data = 0;
-
-	if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD)
-		mrq->need_card_int = 1;
-	else
-		mrq->need_card_int = 0;
-}
-EXPORT_SYMBOL(memstick_init_req);
 
 /*
  * Functions prefixed with "h_" are protocol callbacks. They can be called from
@@ -362,20 +249,6 @@ static int h_memstick_set_rw_addr(struct memstick_dev *card,
 	}
 }
 
-/**
- * memstick_set_rw_addr - issue SET_RW_REG_ADDR request and wait for it to
- *                        complete
- * @card - media device to use
- */
-int memstick_set_rw_addr(struct memstick_dev *card)
-{
-	card->next_request = h_memstick_set_rw_addr;
-	memstick_new_req(card->host);
-	wait_for_completion(&card->mrq_complete);
-
-	return card->current_mrq.error;
-}
-EXPORT_SYMBOL(memstick_set_rw_addr);
 
 static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
 {
@@ -418,7 +291,7 @@ err_out:
 	return NULL;
 }
 
-static int memstick_power_on(struct memstick_host *host)
+int memstick_power_on(struct memstick_host *host)
 {
 	int rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON);
 
@@ -480,6 +353,125 @@ out_power_off:
 	dev_dbg(&host->dev, "memstick_check finished\n");
 }
 
+/*** card driver interface ***/
+
+/**
+  * memstick_register_driver - Register new card driver
+  * @drv - the driver descriptior
+  */
+
+int memstick_register_driver(struct memstick_driver *drv)
+{
+	drv->driver.bus = &memstick_bus_type;
+
+	return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(memstick_register_driver);
+
+/**
+  * memstick_unregister_driver - deregister new card driver
+  * @drv - the driver descriptior
+  */
+
+void memstick_unregister_driver(struct memstick_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(memstick_unregister_driver);
+
+
+/**
+ * memstick_set_rw_addr - issue SET_RW_REG_ADDR request and wait for it to
+ *                        complete
+ * @card - media device to use
+ */
+int memstick_set_rw_addr(struct memstick_dev *card)
+{
+	card->next_request = h_memstick_set_rw_addr;
+	memstick_new_req(card->host);
+	wait_for_completion(&card->mrq_complete);
+
+	return card->current_mrq.error;
+}
+EXPORT_SYMBOL(memstick_set_rw_addr);
+
+
+
+
+/**
+ * memstick_new_req - notify the host that some requests are pending
+ * @host - host to use
+ */
+void memstick_new_req(struct memstick_host *host)
+{
+	if (host->card) {
+		host->retries = cmd_retries;
+		INIT_COMPLETION(host->card->mrq_complete);
+		host->request(host);
+	}
+}
+EXPORT_SYMBOL(memstick_new_req);
+
+/**
+ * memstick_init_req_sg - set request fields needed for bulk data transfer
+ * @mrq - request to use
+ * @tpc - memstick Transport Protocol Command
+ * @sg - TPC argument
+ */
+void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
+			  const struct scatterlist *sg)
+{
+	mrq->tpc = tpc;
+	if (tpc & 8)
+		mrq->data_dir = WRITE;
+	else
+		mrq->data_dir = READ;
+
+	mrq->sg = *sg;
+	mrq->long_data = 1;
+
+	if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD)
+		mrq->need_card_int = 1;
+	else
+		mrq->need_card_int = 0;
+}
+EXPORT_SYMBOL(memstick_init_req_sg);
+
+/**
+ * memstick_init_req - set request fields needed for short data transfer
+ * @mrq - request to use
+ * @tpc - memstick Transport Protocol Command
+ * @buf - TPC argument buffer
+ * @length - TPC argument size
+ *
+ * The intended use of this function (transfer of data items several bytes
+ * in size) allows us to just copy the value between request structure and
+ * user supplied buffer.
+ */
+void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
+		       const void *buf, size_t length)
+{
+	mrq->tpc = tpc;
+	if (tpc & 8)
+		mrq->data_dir = WRITE;
+	else
+		mrq->data_dir = READ;
+
+	mrq->data_len = length > sizeof(mrq->data) ? sizeof(mrq->data) : length;
+	if (mrq->data_dir == WRITE)
+		memcpy(mrq->data, buf, mrq->data_len);
+
+	mrq->long_data = 0;
+
+	if (tpc == MS_TPC_SET_CMD || tpc == MS_TPC_EX_SET_CMD)
+		mrq->need_card_int = 1;
+	else
+		mrq->need_card_int = 0;
+}
+EXPORT_SYMBOL(memstick_init_req);
+
+/*** low level (host) driver interface ***/
+
 /**
  * memstick_alloc_host - allocate a memstick_host structure
  * @extra: size of the user private data to allocate
@@ -597,19 +589,48 @@ void memstick_resume_host(struct memstick_host *host)
 }
 EXPORT_SYMBOL(memstick_resume_host);
 
-int memstick_register_driver(struct memstick_driver *drv)
-{
-	drv->driver.bus = &memstick_bus_type;
 
-	return driver_register(&drv->driver);
+/**
+ * memstick_detect_change - schedule media detection on memstick host
+ * @host - host to use
+ */
+void memstick_detect_change(struct memstick_host *host)
+{
+	queue_work(workqueue, &host->media_checker);
 }
-EXPORT_SYMBOL(memstick_register_driver);
+EXPORT_SYMBOL(memstick_detect_change);
 
-void memstick_unregister_driver(struct memstick_driver *drv)
+/**
+ * memstick_next_req - called by host driver to obtain next request to process
+ * @host - host to use
+ * @mrq - pointer to stick the request to
+ *
+ * Host calls this function from idle state (*mrq == NULL) or after finishing
+ * previous request (*mrq should point to it). If previous request was
+ * unsuccessful, it is retried for predetermined number of times. Return value
+ * of 0 means that new request was assigned to the host.
+ */
+int memstick_next_req(struct memstick_host *host, struct memstick_request **mrq)
 {
-	driver_unregister(&drv->driver);
+	int rc = -ENXIO;
+
+	if ((*mrq) && (*mrq)->error && host->retries) {
+		(*mrq)->error = rc;
+		host->retries--;
+		return 0;
+	}
+
+	if (host->card && host->card->next_request)
+		rc = host->card->next_request(host->card, mrq);
+
+	if (!rc)
+		host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1;
+	else
+		*mrq = NULL;
+
+	return rc;
 }
-EXPORT_SYMBOL(memstick_unregister_driver);
+EXPORT_SYMBOL(memstick_next_req);
 
 
 static int __init memstick_init(void)
diff --git a/include/linux/memstick.h b/include/linux/memstick.h
index 5479f7d..428c4a1 100644
--- a/include/linux/memstick.h
+++ b/include/linux/memstick.h
@@ -332,42 +332,52 @@ struct memstick_driver {
 	struct device_driver      driver;
 };
 
+/* interface  for high-level (card) drivers */
+
+static inline void *memstick_get_drvdata(struct memstick_dev *card)
+{
+	return dev_get_drvdata(&card->dev);
+}
+
+static inline void memstick_set_drvdata(struct memstick_dev *card, void *data)
+{
+	dev_set_drvdata(&card->dev, data);
+}
+
 int memstick_register_driver(struct memstick_driver *drv);
 void memstick_unregister_driver(struct memstick_driver *drv);
 
+int memstick_set_rw_addr(struct memstick_dev *card);
+
+void memstick_new_req(struct memstick_host *host);
+
+void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
+			  const struct scatterlist *sg);
+void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
+		       const void *buf, size_t length);
+
+/* Interface for low-level (host) drivers */
+
 struct memstick_host *memstick_alloc_host(unsigned int extra,
 					  struct device *dev);
 
 int memstick_add_host(struct memstick_host *host);
 void memstick_remove_host(struct memstick_host *host);
 void memstick_free_host(struct memstick_host *host);
-void memstick_detect_change(struct memstick_host *host);
+
+
 void memstick_suspend_host(struct memstick_host *host);
 void memstick_resume_host(struct memstick_host *host);
 
-void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
-			  const struct scatterlist *sg);
-void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
-		       const void *buf, size_t length);
+void memstick_detect_change(struct memstick_host *host);
+
 int memstick_next_req(struct memstick_host *host,
 		      struct memstick_request **mrq);
-void memstick_new_req(struct memstick_host *host);
 
-int memstick_set_rw_addr(struct memstick_dev *card);
 
 static inline void *memstick_priv(struct memstick_host *host)
 {
 	return (void *)host->private;
 }
 
-static inline void *memstick_get_drvdata(struct memstick_dev *card)
-{
-	return dev_get_drvdata(&card->dev);
-}
-
-static inline void memstick_set_drvdata(struct memstick_dev *card, void *data)
-{
-	dev_set_drvdata(&card->dev, data);
-}
-
 #endif
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 03/29] memstick: core: add new functions
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
  2010-10-22 23:53 ` [PATCH 01/29] memstick: core: header cleanups Maxim Levitsky
  2010-10-22 23:53 ` [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 14:56   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 04/29] memstick: core: rework state machines Maxim Levitsky
                   ` (26 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Add a lot of support code that will be used later.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/memstick.c |  299 ++++++++++++++++++++++++++++++++++++--
 include/linux/memstick.h         |   32 ++++
 2 files changed, 318 insertions(+), 13 deletions(-)

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 5a501a4..9fe36c7 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -249,6 +249,17 @@ static int h_memstick_set_rw_addr(struct memstick_dev *card,
 	}
 }
 
+static int h_memstick_default_bad(struct memstick_dev *card,
+				     struct memstick_request **mrq)
+{
+	return -ENXIO;
+}
+
+static void memstick_invalidate_reg_window(struct memstick_dev *card)
+{
+	memset(&card->reg_addr, 0, sizeof(card->reg_addr));
+}
+
 
 static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
 {
@@ -293,14 +304,23 @@ err_out:
 
 int memstick_power_on(struct memstick_host *host)
 {
-	int rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON);
+	int rc;
 
+	if (host->card)
+		memstick_invalidate_reg_window(host->card);
+
+	rc = host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON);
 	if (!rc)
 		rc = host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL);
 
 	return rc;
 }
 
+int memstick_power_off(struct memstick_host *host)
+{
+	return host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
+}
+
 static void memstick_check(struct work_struct *work)
 {
 	struct memstick_host *host = container_of(work, struct memstick_host,
@@ -347,7 +367,7 @@ static void memstick_check(struct work_struct *work)
 
 out_power_off:
 	if (!host->card)
-		host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
+		memstick_power_off(host);
 
 	mutex_unlock(&host->lock);
 	dev_dbg(&host->dev, "memstick_check finished\n");
@@ -356,10 +376,9 @@ out_power_off:
 /*** card driver interface ***/
 
 /**
-  * memstick_register_driver - Register new card driver
-  * @drv - the driver descriptior
-  */
-
+ * memstick_register_driver - register new card driver
+ * @drv - the driver info structure
+ */
 int memstick_register_driver(struct memstick_driver *drv)
 {
 	drv->driver.bus = &memstick_bus_type;
@@ -369,10 +388,10 @@ int memstick_register_driver(struct memstick_driver *drv)
 EXPORT_SYMBOL(memstick_register_driver);
 
 /**
-  * memstick_unregister_driver - deregister new card driver
-  * @drv - the driver descriptior
-  */
-
+ * memstick_unregister_driver - unregister a card driver
+ * usually called on card driver unload
+ * @drv - the driver info structure
+ */
 void memstick_unregister_driver(struct memstick_driver *drv)
 {
 	driver_unregister(&drv->driver);
@@ -396,8 +415,6 @@ int memstick_set_rw_addr(struct memstick_dev *card)
 EXPORT_SYMBOL(memstick_set_rw_addr);
 
 
-
-
 /**
  * memstick_new_req - notify the host that some requests are pending
  * @host - host to use
@@ -412,6 +429,93 @@ void memstick_new_req(struct memstick_host *host)
 }
 EXPORT_SYMBOL(memstick_new_req);
 
+
+/*** state machine support code ***/
+
+/**
+ * memstick_run_state_machine - runs IO state machine
+ * DON'T call from state machine code!
+ * Usefull for blocking IO in the card drivers.
+ * @card - card to use
+ * @state_func - the state machine
+ * @sync - if true, will wait till state machine exits using
+ * memstick_exit_state_machine
+ */
+int memstick_run_state_machine(struct memstick_dev *card,
+	int   (*state_func)(struct memstick_dev *card,
+			struct memstick_request **mrq), bool sync)
+{
+	WARN_ON(card->state != -1);
+
+	/* Init everything to prevent stale data from creeping in */
+	memset(&card->current_mrq, 0, sizeof(card->current_mrq));
+	card->int_polling = false;
+	card->state = 0;
+	card->exit_error = 0;
+
+
+	card->next_request = state_func;
+	card->host->retries = cmd_retries;
+	INIT_COMPLETION(card->mrq_complete);
+	card->host->request(card->host);
+
+	if (!sync)
+		return 0;
+
+	wait_for_completion(&card->mrq_complete);
+
+	WARN_ON(card->state != -1);
+	return card->exit_error;
+}
+EXPORT_SYMBOL(memstick_run_state_machine);
+
+
+/**
+ * memstick_exit_state_machine - signal that request is completed
+ * @card - card to use
+ * @mrq - request to use
+ * @error - result of the request
+ *
+ * State machines call this to signal quit
+ */
+int memstick_exit_state_machine(struct memstick_dev *card,
+			struct memstick_request *req, int error)
+{
+	if (error)
+		req->error = error;
+
+	card->state = -1;
+	card->exit_error = error;
+	card->next_request = h_memstick_default_bad;
+
+	/* Invalidate reg window on errors */
+	if (error)
+		memstick_invalidate_reg_window(card);
+
+	complete(&card->mrq_complete);
+	return -ENXIO;
+}
+EXPORT_SYMBOL(memstick_exit_state_machine);
+
+/**
+ * memstick_allocate_request - create new request for use in request handler
+ * @card - card to use
+ * @mrq - request to initialize
+ */
+void memstick_allocate_request(struct memstick_dev *card,
+					struct memstick_request **mrq)
+{
+	if (*mrq == NULL) {
+		*mrq = &card->current_mrq;
+		(*mrq)->error = 0;
+		(*mrq)->need_card_int = 0;
+		card->int_polling = false;
+		card->state = 0;
+	}
+}
+EXPORT_SYMBOL(memstick_allocate_request);
+
+
 /**
  * memstick_init_req_sg - set request fields needed for bulk data transfer
  * @mrq - request to use
@@ -470,6 +574,175 @@ void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
 }
 EXPORT_SYMBOL(memstick_init_req);
 
+/**
+ * memstick_read_int_reg - read INT status from the card
+ * if last request already contains the int flags, will return 0
+ * returns 1 if new request was initialized
+ * Will artifictially return MEMSTICK_INT_CMDNAK if more that 'timeout' msecs
+ * passed after last MS_TPC_GET_INT request (and no requests in between)
+ * if timeout == -1, then it is set to default value of 500 msec
+ * @card - card to use
+ * @timeout - the timeout. if -1, then uses default
+ */
+int memstick_read_int_reg(struct memstick_dev *card,
+				struct memstick_request *req, long timeout)
+{
+
+	if (!card->int_polling) {
+		card->int_timeout = jiffies +
+			msecs_to_jiffies(timeout == -1 ? 500 : timeout);
+		card->int_polling = true;
+	} else if (time_after(jiffies, card->int_timeout)) {
+		req->data[0] = MEMSTICK_INT_CMDNAK;
+		return 0;
+	}
+
+	if (((card->caps | card->host->caps) & MEMSTICK_CAP_AUTO_GET_INT) &&
+							req->need_card_int) {
+		BUG_ON(req->error);
+		req->data[0] = req->int_reg;
+		req->need_card_int = 0;
+		return 0;
+	} else {
+		memstick_init_req(req, MS_TPC_GET_INT, NULL, 1);
+		return 1;
+	}
+}
+EXPORT_SYMBOL(memstick_read_int_reg);
+
+
+/**
+ * memstick_read_int_reg_cleanup - cleanup after series of calls to
+ * memstick_read_int_reg. Used to cancel timeout.
+ * Use this if you use memstick_read_int_reg
+ * @card - card to use
+ */
+void memstick_read_int_reg_cleanup(struct memstick_dev *card)
+{
+	card->int_polling = false;
+}
+EXPORT_SYMBOL(memstick_read_int_reg_cleanup);
+
+
+/**
+ * memstick_read_regs - read the ms registers
+ * If there is need to change the R/W window,
+ * it will create the MS_TPC_SET_RW_REG_ADRS request and return 0,
+ * otherwise it will create a request for register read and return 1
+ * @card - card to use
+ * @offset - offset of first register to read
+ * @len - number of bytes to read
+ * @req - request to use
+ */
+
+int memstick_read_regs(struct memstick_dev *card, int offset, int len,
+	struct memstick_request *req)
+{
+	if (card->reg_addr.r_offset != offset ||
+					card->reg_addr.r_length != len) {
+		card->reg_addr.r_offset = offset;
+		card->reg_addr.r_length = len;
+
+		/* Set dummy window after reg invalidation to prevent
+			possible rejection of 0,0 window by the card */
+		if (!card->reg_addr.w_length) {
+			card->reg_addr.w_offset =
+					offsetof(struct ms_register, id);
+			card->reg_addr.w_length = sizeof(struct ms_id_register);
+		}
+
+		memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
+			sizeof(card->reg_addr));
+		return 0;
+	}
+
+	memstick_init_req(req, MS_TPC_READ_REG, NULL, len);
+	return 1;
+}
+EXPORT_SYMBOL(memstick_read_regs);
+
+/**
+ * memstick_write_regs - write the ms registers.
+ * If there is need to change the R/W window,
+ * it will create the MS_TPC_SET_RW_REG_ADRS request and return 0,
+ * otherwise it will create a request for register write and return 1
+ * @card - card to use
+ * @offset - offset of first register to read
+ * @len - number of bytes to read
+ * @buf - the register data to write
+ * @req - request to use
+ */
+int memstick_write_regs(struct memstick_dev *card, int offset, int len,
+	char *buf, struct memstick_request *req)
+{
+	if (card->reg_addr.w_offset != offset ||
+					card->reg_addr.w_length != len) {
+		card->reg_addr.w_offset = offset;
+		card->reg_addr.w_length = len;
+
+		/* Set dummy window after reg invalidation to prevent
+			possible rejection of 0,0 window by the card */
+		if (!card->reg_addr.r_length) {
+			card->reg_addr.r_offset =
+					offsetof(struct ms_register, id);
+
+			card->reg_addr.r_length = sizeof(struct ms_id_register);
+		}
+
+		memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
+			sizeof(card->reg_addr));
+		return 0;
+	}
+
+	memstick_init_req(req, MS_TPC_WRITE_REG, buf, len);
+	return 1;
+}
+EXPORT_SYMBOL(memstick_write_regs);
+
+
+static const char *tpc_names[] = {
+	"MS_TPC_READ_MG_STATUS",
+	"MS_TPC_READ_LONG_DATA",
+	"MS_TPC_READ_SHORT_DATA",
+	"MS_TPC_READ_REG",
+	"MS_TPC_READ_QUAD_DATA",
+	"INVALID",
+	"MS_TPC_GET_INT",
+	"MS_TPC_SET_RW_REG_ADRS",
+	"MS_TPC_EX_SET_CMD",
+	"MS_TPC_WRITE_QUAD_DATA",
+	"MS_TPC_WRITE_REG",
+	"MS_TPC_WRITE_SHORT_DATA",
+	"MS_TPC_WRITE_LONG_DATA",
+	"MS_TPC_SET_CMD",
+};
+
+/**
+ * memstick_debug_get_tpc_name - debug helper that returns string for
+ * a TPC number
+ */
+const char *memstick_debug_get_tpc_name(int tpc)
+{
+	return tpc_names[tpc-1];
+}
+EXPORT_SYMBOL(memstick_debug_get_tpc_name);
+
+/**
+ * memstick_reset - power cycles the host
+ */
+int memstick_reset(struct memstick_host *host)
+{
+	int error = memstick_power_off(host);
+	if (error)
+		return error;
+
+	/* TODO: why this delay ? */
+	msleep(50);
+
+	return memstick_power_on(host);
+}
+EXPORT_SYMBOL(memstick_reset);
+
 /*** low level (host) driver interface ***/
 
 /**
@@ -566,7 +839,7 @@ EXPORT_SYMBOL(memstick_free_host);
 void memstick_suspend_host(struct memstick_host *host)
 {
 	mutex_lock(&host->lock);
-	host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
+	memstick_power_off(host);
 	mutex_unlock(&host->lock);
 }
 EXPORT_SYMBOL(memstick_suspend_host);
diff --git a/include/linux/memstick.h b/include/linux/memstick.h
index 428c4a1..73586cb 100644
--- a/include/linux/memstick.h
+++ b/include/linux/memstick.h
@@ -296,6 +296,13 @@ struct memstick_dev {
 	void                     (*start)(struct memstick_dev *card);
 
 	struct device            dev;
+	int			 caps;
+
+	/* state machine's state */
+	int			 state;
+	int			 exit_error;
+	bool			 int_polling;
+	unsigned long		 int_timeout;
 };
 
 struct memstick_host {
@@ -349,6 +356,16 @@ void memstick_unregister_driver(struct memstick_driver *drv);
 
 int memstick_set_rw_addr(struct memstick_dev *card);
 
+int memstick_run_state_machine(struct memstick_dev *card,
+	int   (*state_func)(struct memstick_dev *card,
+			struct memstick_request **mrq), bool sync);
+
+int memstick_exit_state_machine(struct memstick_dev *card,
+			struct memstick_request *req, int error);
+
+void memstick_allocate_request(struct memstick_dev *card,
+					struct memstick_request **mrq);
+
 void memstick_new_req(struct memstick_host *host);
 
 void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
@@ -356,6 +373,21 @@ void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
 void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
 		       const void *buf, size_t length);
 
+int memstick_read_int_reg(struct memstick_dev *card,
+				struct memstick_request *req, long timeout);
+
+void memstick_read_int_reg_cleanup(struct memstick_dev *card);
+
+int memstick_read_regs(struct memstick_dev *card, int offset, int len,
+	struct memstick_request *req);
+
+int memstick_write_regs(struct memstick_dev *card, int offset, int len,
+	char *buf, struct memstick_request *req);
+
+const char *memstick_debug_get_tpc_name(int tpc);
+
+int memstick_reset(struct memstick_host *host);
+
 /* Interface for low-level (host) drivers */
 
 struct memstick_host *memstick_alloc_host(unsigned int extra,
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 04/29] memstick: core: rework state machines
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (2 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 03/29] memstick: core: add new functions Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:01   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit Maxim Levitsky
                   ` (25 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Make state machines in memstick core follow the
new style.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/memstick.c |   82 ++++++++++++++++++++-----------------
 1 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 9fe36c7..e1aa089 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -211,44 +211,57 @@ static int memstick_dummy_check(struct memstick_dev *card)
  */
 
 static int h_memstick_read_dev_id(struct memstick_dev *card,
-				  struct memstick_request **mrq)
+						struct memstick_request **mrq)
 {
 	struct ms_id_register id_reg;
 
-	if (!(*mrq)) {
-		memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL,
-				  sizeof(struct ms_id_register));
-		*mrq = &card->current_mrq;
-		return 0;
-	} else {
-		if (!(*mrq)->error) {
-			memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
-			card->id.match_flags = MEMSTICK_MATCH_ALL;
-			card->id.type = id_reg.type;
-			card->id.category = id_reg.category;
-			card->id.class = id_reg.class;
-			dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode);
-		}
-		complete(&card->mrq_complete);
-		return -EAGAIN;
+	memstick_allocate_request(card, mrq);
+	if ((*mrq)->error)
+		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+
+	switch (card->state) {
+	case 0:
+		if (!memstick_read_regs(card,
+			offsetof(struct ms_register, id),
+			sizeof(struct ms_id_register), *mrq))
+			return 0;
+		break;
+	case 1:
+		memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
+		card->id.match_flags = MEMSTICK_MATCH_ALL;
+		card->id.type = id_reg.type;
+		card->id.category = id_reg.category;
+		card->id.class = id_reg.class;
+		dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode);
+		return memstick_exit_state_machine(card, *mrq, 0);
 	}
+
+	card->state++;
+	return 0;
 }
 
 static int h_memstick_set_rw_addr(struct memstick_dev *card,
 				  struct memstick_request **mrq)
 {
-	if (!(*mrq)) {
-		memstick_init_req(&card->current_mrq, MS_TPC_SET_RW_REG_ADRS,
+	memstick_allocate_request(card, mrq);
+	if ((*mrq)->error)
+		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+
+	switch (card->state) {
+	case 0:
+		memstick_init_req(*mrq, MS_TPC_SET_RW_REG_ADRS,
 				  (char *)&card->reg_addr,
 				  sizeof(card->reg_addr));
-		*mrq = &card->current_mrq;
-		return 0;
-	} else {
-		complete(&card->mrq_complete);
-		return -EAGAIN;
+		break;
+	case 1:
+		return memstick_exit_state_machine(card, *mrq, 0);
 	}
+
+	card->state++;
+	return 0;
 }
 
+
 static int h_memstick_default_bad(struct memstick_dev *card,
 				     struct memstick_request **mrq)
 {
@@ -281,18 +294,18 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
 		card->reg_addr.w_offset = offsetof(struct ms_register, id);
 		card->reg_addr.w_length = sizeof(id_reg);
 
+		host->card = card;
 		init_completion(&card->mrq_complete);
+		card->state = -1;
+		card->next_request = h_memstick_default_bad;
 
-		host->card = card;
 		if (memstick_set_rw_addr(card))
 			goto err_out;
 
-		card->next_request = h_memstick_read_dev_id;
-		memstick_new_req(host);
-		wait_for_completion(&card->mrq_complete);
-
-		if (card->current_mrq.error)
+		if (memstick_run_state_machine(card,
+						h_memstick_read_dev_id, true))
 			goto err_out;
+
 	}
 	host->card = old_card;
 	return card;
@@ -406,11 +419,7 @@ EXPORT_SYMBOL(memstick_unregister_driver);
  */
 int memstick_set_rw_addr(struct memstick_dev *card)
 {
-	card->next_request = h_memstick_set_rw_addr;
-	memstick_new_req(card->host);
-	wait_for_completion(&card->mrq_complete);
-
-	return card->current_mrq.error;
+	return memstick_run_state_machine(card, h_memstick_set_rw_addr, true);
 }
 EXPORT_SYMBOL(memstick_set_rw_addr);
 
@@ -481,9 +490,6 @@ EXPORT_SYMBOL(memstick_run_state_machine);
 int memstick_exit_state_machine(struct memstick_dev *card,
 			struct memstick_request *req, int error)
 {
-	if (error)
-		req->error = error;
-
 	card->state = -1;
 	card->exit_error = error;
 	card->next_request = h_memstick_default_bad;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (3 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 04/29] memstick: core: rework state machines Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:07   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 06/29] memstick: mspro: kill the BKL Maxim Levitsky
                   ` (24 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

This makes it much easier to lookup things and reduces size of mspro_block.c
Also add debbuging macros so that it becames possible to control
debbuging via module param.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/mspro_block.c |  157 ++-----------------------------
 drivers/memstick/core/mspro_block.h |  176 +++++++++++++++++++++++++++++++++++
 2 files changed, 185 insertions(+), 148 deletions(-)
 create mode 100644 drivers/memstick/core/mspro_block.h

diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index d3f1a08..5dc8fd7 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -20,158 +20,14 @@
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/memstick.h>
-
-#define DRIVER_NAME "mspro_block"
+#include "mspro_block.h"
 
 static int major;
-module_param(major, int, 0644);
-
-#define MSPRO_BLOCK_MAX_SEGS  32
-#define MSPRO_BLOCK_MAX_PAGES ((2 << 16) - 1)
-
-#define MSPRO_BLOCK_SIGNATURE        0xa5c3
-#define MSPRO_BLOCK_MAX_ATTRIBUTES   41
-
-#define MSPRO_BLOCK_PART_SHIFT 3
-
-enum {
-	MSPRO_BLOCK_ID_SYSINFO         = 0x10,
-	MSPRO_BLOCK_ID_MODELNAME       = 0x15,
-	MSPRO_BLOCK_ID_MBR             = 0x20,
-	MSPRO_BLOCK_ID_PBR16           = 0x21,
-	MSPRO_BLOCK_ID_PBR32           = 0x22,
-	MSPRO_BLOCK_ID_SPECFILEVALUES1 = 0x25,
-	MSPRO_BLOCK_ID_SPECFILEVALUES2 = 0x26,
-	MSPRO_BLOCK_ID_DEVINFO         = 0x30
-};
-
-struct mspro_sys_attr {
-	size_t                  size;
-	void                    *data;
-	unsigned char           id;
-	char                    name[32];
-	struct device_attribute dev_attr;
-};
-
-struct mspro_attr_entry {
-	__be32 address;
-	__be32 size;
-	unsigned char id;
-	unsigned char reserved[3];
-} __attribute__((packed));
-
-struct mspro_attribute {
-	__be16 signature;
-	unsigned short          version;
-	unsigned char           count;
-	unsigned char           reserved[11];
-	struct mspro_attr_entry entries[];
-} __attribute__((packed));
-
-struct mspro_sys_info {
-	unsigned char  class;
-	unsigned char  reserved0;
-	__be16 block_size;
-	__be16 block_count;
-	__be16 user_block_count;
-	__be16 page_size;
-	unsigned char  reserved1[2];
-	unsigned char  assembly_date[8];
-	__be32 serial_number;
-	unsigned char  assembly_maker_code;
-	unsigned char  assembly_model_code[3];
-	__be16 memory_maker_code;
-	__be16 memory_model_code;
-	unsigned char  reserved2[4];
-	unsigned char  vcc;
-	unsigned char  vpp;
-	__be16 controller_number;
-	__be16 controller_function;
-	__be16 start_sector;
-	__be16 unit_size;
-	unsigned char  ms_sub_class;
-	unsigned char  reserved3[4];
-	unsigned char  interface_type;
-	__be16 controller_code;
-	unsigned char  format_type;
-	unsigned char  reserved4;
-	unsigned char  device_type;
-	unsigned char  reserved5[7];
-	unsigned char  mspro_id[16];
-	unsigned char  reserved6[16];
-} __attribute__((packed));
-
-struct mspro_mbr {
-	unsigned char boot_partition;
-	unsigned char start_head;
-	unsigned char start_sector;
-	unsigned char start_cylinder;
-	unsigned char partition_type;
-	unsigned char end_head;
-	unsigned char end_sector;
-	unsigned char end_cylinder;
-	unsigned int  start_sectors;
-	unsigned int  sectors_per_partition;
-} __attribute__((packed));
-
-struct mspro_specfile {
-	char           name[8];
-	char           ext[3];
-	unsigned char  attr;
-	unsigned char  reserved[10];
-	unsigned short time;
-	unsigned short date;
-	unsigned short cluster;
-	unsigned int   size;
-} __attribute__((packed));
-
-struct mspro_devinfo {
-	__be16 cylinders;
-	__be16 heads;
-	__be16 bytes_per_track;
-	__be16 bytes_per_sector;
-	__be16 sectors_per_track;
-	unsigned char  reserved[6];
-} __attribute__((packed));
-
-struct mspro_block_data {
-	struct memstick_dev   *card;
-	unsigned int          usage_count;
-	unsigned int          caps;
-	struct gendisk        *disk;
-	struct request_queue  *queue;
-	struct request        *block_req;
-	spinlock_t            q_lock;
-
-	unsigned short        page_size;
-	unsigned short        cylinders;
-	unsigned short        heads;
-	unsigned short        sectors_per_track;
-
-	unsigned char         system;
-	unsigned char         read_only:1,
-			      eject:1,
-			      has_request:1,
-			      data_dir:1,
-			      active:1;
-	unsigned char         transfer_cmd;
-
-	int                   (*mrq_handler)(struct memstick_dev *card,
-					     struct memstick_request **mrq);
-
-	struct attribute_group attr_group;
-
-	struct scatterlist    req_sg[MSPRO_BLOCK_MAX_SEGS];
-	unsigned int          seg_count;
-	unsigned int          current_seg;
-	unsigned int          current_page;
-};
+static int debug;
 
 static DEFINE_IDR(mspro_block_disk_idr);
 static DEFINE_MUTEX(mspro_block_disk_lock);
 
-static int mspro_block_complete_req(struct memstick_dev *card, int error);
-
 /*** Block device ***/
 
 static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode)
@@ -1202,6 +1058,7 @@ static int mspro_block_init_disk(struct memstick_dev *card)
 	msb->cylinders = be16_to_cpu(dev_info->cylinders);
 	msb->heads = be16_to_cpu(dev_info->heads);
 	msb->sectors_per_track = be16_to_cpu(dev_info->sectors_per_track);
+	sg_init_table(msb->req_sg, MSPRO_BLOCK_MAX_SEGS);
 
 	msb->page_size = be16_to_cpu(sys_info->unit_size);
 
@@ -1257,7 +1114,7 @@ static int mspro_block_init_disk(struct memstick_dev *card)
 	capacity *= be16_to_cpu(sys_info->block_size);
 	capacity *= msb->page_size >> 9;
 	set_capacity(msb->disk, capacity);
-	dev_dbg(&card->dev, "capacity set %ld\n", capacity);
+	dbg(card, "capacity set %ld", capacity);
 
 	add_disk(msb->disk);
 	msb->active = 1;
@@ -1345,7 +1202,7 @@ static void mspro_block_remove(struct memstick_dev *card)
 	spin_unlock_irqrestore(&msb->q_lock, flags);
 
 	del_gendisk(msb->disk);
-	dev_dbg(&card->dev, "mspro block remove\n");
+	dbg(card, "mspro block remove");
 
 	blk_cleanup_queue(msb->queue);
 	msb->queue = NULL;
@@ -1485,6 +1342,10 @@ static void __exit mspro_block_exit(void)
 module_init(mspro_block_init);
 module_exit(mspro_block_exit);
 
+module_param(major, int, 0644);
+module_param(debug, int, 0644);
+
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alex Dubov");
 MODULE_DESCRIPTION("Sony MemoryStickPro block device driver");
diff --git a/drivers/memstick/core/mspro_block.h b/drivers/memstick/core/mspro_block.h
new file mode 100644
index 0000000..afb29f8
--- /dev/null
+++ b/drivers/memstick/core/mspro_block.h
@@ -0,0 +1,176 @@
+/*
+ *  Sony MemoryStick Pro storage support
+ *
+ *  Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
+ *  Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Special thanks to Carlos Corbacho for providing various MemoryStick cards
+ * that made this driver possible.
+ *
+ */
+
+#define DRIVER_NAME "mspro_block"
+
+#define MSPRO_BLOCK_MAX_SEGS  32
+#define MSPRO_BLOCK_MAX_PAGES ((2 << 16) - 1)
+
+#define MSPRO_BLOCK_SIGNATURE        0xa5c3
+#define MSPRO_BLOCK_MAX_ATTRIBUTES   41
+
+#define MSPRO_BLOCK_PART_SHIFT 3
+
+enum {
+	MSPRO_BLOCK_ID_SYSINFO         = 0x10,
+	MSPRO_BLOCK_ID_MODELNAME       = 0x15,
+	MSPRO_BLOCK_ID_MBR             = 0x20,
+	MSPRO_BLOCK_ID_PBR16           = 0x21,
+	MSPRO_BLOCK_ID_PBR32           = 0x22,
+	MSPRO_BLOCK_ID_SPECFILEVALUES1 = 0x25,
+	MSPRO_BLOCK_ID_SPECFILEVALUES2 = 0x26,
+	MSPRO_BLOCK_ID_DEVINFO         = 0x30
+};
+
+struct mspro_sys_attr {
+	size_t                  size;
+	void                    *data;
+	unsigned char           id;
+	char                    name[32];
+	struct device_attribute dev_attr;
+};
+
+struct mspro_attr_entry {
+	__be32 address;
+	__be32 size;
+	unsigned char id;
+	unsigned char reserved[3];
+} __packed;
+
+struct mspro_attribute {
+	__be16 signature;
+	unsigned short          version;
+	unsigned char           count;
+	unsigned char           reserved[11];
+	struct mspro_attr_entry entries[];
+} __packed;
+
+struct mspro_sys_info {
+	unsigned char  class;
+	unsigned char  reserved0;
+	__be16 block_size;
+	__be16 block_count;
+	__be16 user_block_count;
+	__be16 page_size;
+	unsigned char  reserved1[2];
+	unsigned char  assembly_date[8];
+	__be32 serial_number;
+	unsigned char  assembly_maker_code;
+	unsigned char  assembly_model_code[3];
+	__be16 memory_maker_code;
+	__be16 memory_model_code;
+	unsigned char  reserved2[4];
+	unsigned char  vcc;
+	unsigned char  vpp;
+	__be16 controller_number;
+	__be16 controller_function;
+	__be16 start_sector;
+	__be16 unit_size;
+	unsigned char  ms_sub_class;
+	unsigned char  reserved3[4];
+	unsigned char  interface_type;
+	__be16 controller_code;
+	unsigned char  format_type;
+	unsigned char  reserved4;
+	unsigned char  device_type;
+	unsigned char  reserved5[7];
+	unsigned char  mspro_id[16];
+	unsigned char  reserved6[16];
+} __packed;
+
+struct mspro_mbr {
+	unsigned char boot_partition;
+	unsigned char start_head;
+	unsigned char start_sector;
+	unsigned char start_cylinder;
+	unsigned char partition_type;
+	unsigned char end_head;
+	unsigned char end_sector;
+	unsigned char end_cylinder;
+	unsigned int  start_sectors;
+	unsigned int  sectors_per_partition;
+} __packed;
+
+struct mspro_specfile {
+	char           name[8];
+	char           ext[3];
+	unsigned char  attr;
+	unsigned char  reserved[10];
+	unsigned short time;
+	unsigned short date;
+	unsigned short cluster;
+	unsigned int   size;
+} __packed;
+
+struct mspro_devinfo {
+	__be16 cylinders;
+	__be16 heads;
+	__be16 bytes_per_track;
+	__be16 bytes_per_sector;
+	__be16 sectors_per_track;
+	unsigned char  reserved[6];
+} __packed;
+
+
+
+struct mspro_block_data {
+	struct memstick_dev   *card;
+	unsigned int          usage_count;
+	unsigned int          caps;
+	struct gendisk        *disk;
+	struct request_queue  *queue;
+	struct request        *block_req;
+	spinlock_t            q_lock;
+
+	unsigned short        page_size;
+	unsigned short        cylinders;
+	unsigned short        heads;
+	unsigned short        sectors_per_track;
+
+	unsigned char         system;
+	unsigned char         read_only:1,
+			      eject:1,
+			      has_request:1,
+			      data_dir:1,
+			      active:1;
+	unsigned char         transfer_cmd;
+
+	int                   (*mrq_handler)(struct memstick_dev *card,
+					     struct memstick_request **mrq);
+
+	struct attribute_group attr_group;
+
+	struct scatterlist    req_sg[MSPRO_BLOCK_MAX_SEGS];
+	unsigned int          seg_count;
+	unsigned int          current_seg;
+	unsigned int          current_page;
+};
+
+static int mspro_block_complete_req(struct memstick_dev *card, int error);
+static int mspro_block_switch_interface(struct memstick_dev *card);
+static int mspro_block_issue_req(struct memstick_dev *card, int chunk);
+
+#define __dbg(card, level, format, ...) \
+	do { \
+		if (debug >= level) \
+			printk(KERN_DEBUG \
+				"%s: " format "\n", dev_name(&card->dev) \
+					 , ## __VA_ARGS__); \
+		else \
+			dev_dbg(&card->dev, format, ## __VA_ARGS__); \
+	} while (0)
+
+#define dbg(card, format, ...)		__dbg(card, 1, format, ## __VA_ARGS__)
+#define dbg_v(card, format, ...)	__dbg(card, 2, format, ## __VA_ARGS__)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 06/29] memstick: mspro: kill the BKL
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (4 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:12   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 07/29] memstick: mspro: two fixes Maxim Levitsky
                   ` (23 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

mspro_block_disk_lock already protects the code.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/mspro_block.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 5dc8fd7..a979c9d 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -36,7 +36,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode)
 	struct mspro_block_data *msb = disk->private_data;
 	int rc = -ENXIO;
 
-	lock_kernel();
 	mutex_lock(&mspro_block_disk_lock);
 
 	if (msb && msb->card) {
@@ -48,8 +47,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode)
 	}
 
 	mutex_unlock(&mspro_block_disk_lock);
-	unlock_kernel();
-
 	return rc;
 }
 
@@ -74,16 +71,13 @@ static int mspro_block_disk_release(struct gendisk *disk)
 	}
 
 	mutex_unlock(&mspro_block_disk_lock);
-
 	return 0;
 }
 
 static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode)
 {
 	int ret;
-	lock_kernel();
 	ret = mspro_block_disk_release(disk);
-	unlock_kernel();
 	return ret;
 }
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 07/29] memstick: mspro: two fixes
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (5 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 06/29] memstick: mspro: kill the BKL Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:13   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 08/29] memstick: mspro: add comments to few functions Maxim Levitsky
                   ` (22 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

fix uninitialized spinlock warning on resume
and race in idr_pre_get

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/mspro_block.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index a979c9d..13cb83b 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -485,6 +485,7 @@ has_int_reg:
 		t_offset = msb->req_sg[msb->current_seg].offset;
 		t_offset += msb->current_page * msb->page_size;
 
+		sg_init_table(&t_sg, 1);
 		sg_set_page(&t_sg,
 			    nth_page(sg_page(&(msb->req_sg[msb->current_seg])),
 				     t_offset >> PAGE_SHIFT),
@@ -1056,10 +1057,13 @@ static int mspro_block_init_disk(struct memstick_dev *card)
 
 	msb->page_size = be16_to_cpu(sys_info->unit_size);
 
-	if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL))
+	mutex_lock(&mspro_block_disk_lock);
+
+	if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) {
+		mutex_unlock(&mspro_block_disk_lock);
 		return -ENOMEM;
+	}
 
-	mutex_lock(&mspro_block_disk_lock);
 	rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id);
 	mutex_unlock(&mspro_block_disk_lock);
 
@@ -1248,6 +1252,8 @@ static int mspro_block_resume(struct memstick_dev *card)
 
 	new_msb->card = card;
 	memstick_set_drvdata(card, new_msb);
+	spin_lock_init(&new_msb->q_lock);
+
 	if (mspro_block_init_card(card))
 		goto out_free;
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 08/29] memstick: mspro: add comments to few functions
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (6 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 07/29] memstick: mspro: two fixes Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:18   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 09/29] memstick: rework state machines + attribute read function Maxim Levitsky
                   ` (21 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

a comment before function is not only a good way
to give some information to the reader, but
it serves as a good anchor point for diff so that
it doesn't produce a diff between different
functions (sigh...)

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/mspro_block.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 13cb83b..a7f263d 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -515,6 +515,10 @@ has_int_reg:
 
 /*** Data transfer ***/
 
+/*
+ * Start execution of next block request,
+ * or continue execution of the current one
+ */
 static int mspro_block_issue_req(struct memstick_dev *card, int chunk)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
@@ -575,6 +579,11 @@ try_again:
 	goto try_again;
 }
 
+/*
+ * Completes execution of current block request.
+ *  After execution of this function, the msb->block_req might or might not
+ *  be NULL. If it is, it means we don't have any more requests to process
+ */
 static int mspro_block_complete_req(struct memstick_dev *card, int error)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
@@ -630,6 +639,10 @@ out:
 	return error;
 }
 
+/*
+ * This pauses driver.
+ * Makes sure that driver won't send any commands to the device
+ */
 static void mspro_block_stop(struct memstick_dev *card)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
@@ -651,6 +664,7 @@ static void mspro_block_stop(struct memstick_dev *card)
 	}
 }
 
+/* This undoes effects of mspro_block_stop */
 static void mspro_block_start(struct memstick_dev *card)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 09/29] memstick: rework state machines + attribute read function
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (7 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 08/29] memstick: mspro: add comments to few functions Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:23   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 10/29] memstick: mspro: create _setup_io helper Maxim Levitsky
                   ` (20 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Code is rewritten to use new style of state machines.
Attribute read function is cleaned up and commented sparsely.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/mspro_block.c |  570 +++++++++++++++++------------------
 drivers/memstick/core/mspro_block.h |   67 +++--
 2 files changed, 319 insertions(+), 318 deletions(-)

diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index a7f263d..cf98fa8 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -385,14 +385,9 @@ static int h_mspro_block_req_init(struct memstick_dev *card,
 static int h_mspro_block_default(struct memstick_dev *card,
 				 struct memstick_request **mrq)
 {
-	return mspro_block_complete_req(card, (*mrq)->error);
+	return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
 }
 
-static int h_mspro_block_default_bad(struct memstick_dev *card,
-				     struct memstick_request **mrq)
-{
-	return -ENXIO;
-}
 
 static int h_mspro_block_get_ro(struct memstick_dev *card,
 				struct memstick_request **mrq)
@@ -407,7 +402,7 @@ static int h_mspro_block_get_ro(struct memstick_dev *card,
 			msb->read_only = 0;
 	}
 
-	return mspro_block_complete_req(card, (*mrq)->error);
+	return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
 }
 
 static int h_mspro_block_wait_for_ced(struct memstick_dev *card,
@@ -422,95 +417,146 @@ static int h_mspro_block_wait_for_ced(struct memstick_dev *card,
 			return 0;
 	}
 
-	return mspro_block_complete_req(card, (*mrq)->error);
+	return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
 }
 
 static int h_mspro_block_transfer_data(struct memstick_dev *card,
 				       struct memstick_request **mrq)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	unsigned char t_val = 0;
+	unsigned char intreg = 0, command;
 	struct scatterlist t_sg = { 0 };
+	unsigned long flags;
+	int error;
 	size_t t_offset;
 
-	if ((*mrq)->error)
-		return mspro_block_complete_req(card, (*mrq)->error);
+	memstick_allocate_request(card, mrq);
 
-	switch ((*mrq)->tpc) {
-	case MS_TPC_WRITE_REG:
-		memstick_init_req(*mrq, MS_TPC_SET_CMD, &msb->transfer_cmd, 1);
-		(*mrq)->need_card_int = 1;
-		return 0;
-	case MS_TPC_SET_CMD:
-		t_val = (*mrq)->int_reg;
-		memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);
-		if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT)
-			goto has_int_reg;
-		return 0;
-	case MS_TPC_GET_INT:
-		t_val = (*mrq)->data[0];
-has_int_reg:
-		if (t_val & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) {
-			t_val = MSPRO_CMD_STOP;
-			memstick_init_req(*mrq, MS_TPC_SET_CMD, &t_val, 1);
-			card->next_request = h_mspro_block_default;
+	if ((*mrq)->error) {
+		dbg(card, "IO: error (%d) executing %s", (*mrq)->error,
+			memstick_debug_get_tpc_name((*mrq)->tpc));
+
+		if (!msb->io_error) {
+			msb->io_error = (*mrq)->error;
+			card->state = 6;
+		}
+	}
+again:
+	switch (card->state) {
+
+	case 0: /* send read/write command + args */
+		if (!memstick_write_regs(card,
+			offsetof(struct mspro_register, param),
+			sizeof(struct mspro_param_register),
+			(unsigned char *)&msb->arg, *mrq))
 			return 0;
+		break;
+	case 1:
+		memstick_init_req(*mrq, MS_TPC_SET_CMD,
+					&msb->transfer_cmd, 1);
+		break;
+
+	case 2: /* read the INT register */
+		if (memstick_read_int_reg(card, *mrq, -1))
+			break;
+		card->state++;
+
+	case 3: /* process the int register */
+		intreg = (*mrq)->data[0];
+
+		if (intreg & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) {
+			dbg(card, "IO: card I/O error");
+			card->state = 6;
+			msb->io_error = -EIO;
+			goto again;
 		}
 
-		if (msb->current_page
-		    == (msb->req_sg[msb->current_seg].length
-			/ msb->page_size)) {
-			msb->current_page = 0;
-			msb->current_seg++;
-
-			if (msb->current_seg == msb->seg_count) {
-				if (t_val & MEMSTICK_INT_CED) {
-					return mspro_block_complete_req(card,
-									0);
-				} else {
-					card->next_request
-						= h_mspro_block_wait_for_ced;
-					memstick_init_req(*mrq, MS_TPC_GET_INT,
-							  NULL, 1);
-					return 0;
-				}
+		/* we need CED for last page */
+		if (!msb->current_sg) {
+			if (!(intreg & MEMSTICK_INT_CED)) {
+				card->state--;
+				goto again;
 			}
+
+			memstick_read_int_reg_cleanup(card);
+			card->state = 7;
+			goto again;
 		}
 
-		if (!(t_val & MEMSTICK_INT_BREQ)) {
-			memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);
-			return 0;
+		/* And BREQ for non last... */
+		if (!(intreg & MEMSTICK_INT_BREQ)) {
+			card->state--;
+			goto again;
 		}
 
-		t_offset = msb->req_sg[msb->current_seg].offset;
-		t_offset += msb->current_page * msb->page_size;
+		memstick_read_int_reg_cleanup(card);
+		card->state++;
+
+	case 4: /* init transfer of the data */
+		t_offset = msb->current_sg->offset + msb->current_sg_offset;
 
 		sg_init_table(&t_sg, 1);
-		sg_set_page(&t_sg,
-			    nth_page(sg_page(&(msb->req_sg[msb->current_seg])),
-				     t_offset >> PAGE_SHIFT),
-			    msb->page_size, offset_in_page(t_offset));
-
-		memstick_init_req_sg(*mrq, msb->data_dir == READ
-					   ? MS_TPC_READ_LONG_DATA
-					   : MS_TPC_WRITE_LONG_DATA,
-				     &t_sg);
+		sg_set_page(&t_sg, nth_page(sg_page(msb->current_sg),
+			t_offset >> PAGE_SHIFT), msb->page_size,
+			offset_in_page(t_offset));
+
+		memstick_init_req_sg(*mrq, msb->data_dir == READ ?
+			MS_TPC_READ_LONG_DATA : MS_TPC_WRITE_LONG_DATA, &t_sg);
 		(*mrq)->need_card_int = 1;
-		return 0;
-	case MS_TPC_READ_LONG_DATA:
-	case MS_TPC_WRITE_LONG_DATA:
-		msb->current_page++;
-		if (msb->caps & MEMSTICK_CAP_AUTO_GET_INT) {
-			t_val = (*mrq)->int_reg;
-			goto has_int_reg;
-		} else {
-			memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);
-			return 0;
+		break;
+
+	case 5: /* switch to next page */
+		msb->current_sg_offset += msb->page_size;
+		msb->data_transferred += msb->page_size;
+
+		if (msb->current_sg_offset == msb->current_sg->length) {
+			msb->current_sg_offset = 0;
+			msb->current_sg = sg_next(msb->current_sg);
 		}
 
+		card->state = 2;
+		goto again;
+
+	case 6: /* after a error send STOP command */
+		command = MSPRO_CMD_STOP;
+		memstick_init_req(*mrq, MS_TPC_SET_CMD, &command, 1);
+		break;
+
+	case 7: /* request complete - get next one*/
+		spin_lock_irqsave(&msb->q_lock, flags);
+
+		if (msb->io_error)
+			(*mrq)->error = msb->io_error;
+
+		if (msb->block_req) {
+			mspro_block_complete_req(card, (*mrq)->error);
+			error = mspro_block_issue_req(card, false);
+
+			if (!msb->block_req) {
+				dbg_v(card, "IO: out of requests");
+				error = memstick_exit_state_machine(
+						card, *mrq, (*mrq)->error);
+				spin_unlock_irqrestore(&msb->q_lock, flags);
+				return error;
+			}
+
+			spin_unlock_irqrestore(&msb->q_lock, flags);
+			(*mrq)->error = 0;
+			card->state = 0;
+			goto again;
+
+		} else {
+			error = memstick_exit_state_machine(card,
+							*mrq, (*mrq)->error);
+			spin_unlock_irqrestore(&msb->q_lock, flags);
+			return error;
+		}
 	default:
 		BUG();
 	}
+
+	card->state++;
+	return 0;
 }
 
 /*** Data transfer ***/
@@ -519,64 +565,62 @@ has_int_reg:
  * Start execution of next block request,
  * or continue execution of the current one
  */
-static int mspro_block_issue_req(struct memstick_dev *card, int chunk)
+static int mspro_block_issue_req(struct memstick_dev *card, bool first)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	sector_t t_sec;
-	unsigned int count;
-	struct mspro_param_register param;
-
-try_again:
-	while (chunk) {
-		msb->current_page = 0;
-		msb->current_seg = 0;
-		msb->seg_count = blk_rq_map_sg(msb->block_req->q,
-					       msb->block_req,
-					       msb->req_sg);
-
-		if (!msb->seg_count) {
-			chunk = __blk_end_request_cur(msb->block_req, -ENOMEM);
-			continue;
+	sector_t sec;
+	bool is_read;
+	unsigned int pages;
+again:
+	/* get next request from block core if we don't have one */
+	if (!msb->block_req) {
+		dbg(card, "IO: fetching new request from block queue");
+		msb->block_req = blk_fetch_request(msb->queue);
+		if (!msb->block_req) {
+			dbg(card, "IO: failed, because queue is empty");
+			return -ENXIO;
 		}
+	}
 
-		t_sec = blk_rq_pos(msb->block_req) << 9;
-		sector_div(t_sec, msb->page_size);
+	if (msb->eject) {
+		dbg(card, "IO: Refusing request, because card is removed");
+		__blk_end_request_all(msb->block_req, -ENODEV);
+		msb->block_req = NULL;
+		goto again;
+	}
 
-		count = blk_rq_bytes(msb->block_req);
-		count /= msb->page_size;
+	sec = blk_rq_pos(msb->block_req) << 9;
+	sector_div(sec, msb->page_size);
+	pages = blk_rq_bytes(msb->block_req) / msb->page_size;
 
-		param.system = msb->system;
-		param.data_count = cpu_to_be16(count);
-		param.data_address = cpu_to_be32((uint32_t)t_sec);
-		param.tpc_param = 0;
+	if (!blk_rq_map_sg(msb->block_req->q, msb->block_req, msb->req_sg)) {
+		dbg(card, "IO: out of memory");
+		if (!__blk_end_request_cur(msb->block_req, -ENOMEM))
+			msb->block_req = NULL;
+		goto again;
+	}
 
-		msb->data_dir = rq_data_dir(msb->block_req);
-		msb->transfer_cmd = msb->data_dir == READ
-				    ? MSPRO_CMD_READ_DATA
-				    : MSPRO_CMD_WRITE_DATA;
+	is_read = rq_data_dir(msb->block_req) == READ;
 
-		dev_dbg(&card->dev, "data transfer: cmd %x, "
-			"lba %x, count %x\n", msb->transfer_cmd,
-			be32_to_cpu(param.data_address), count);
+	msb->current_sg_offset = 0;
+	msb->current_sg = msb->req_sg;
+	msb->data_transferred = 0;
+	msb->io_error = 0;
 
-		card->next_request = h_mspro_block_req_init;
-		msb->mrq_handler = h_mspro_block_transfer_data;
-		memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
-				  &param, sizeof(param));
-		memstick_new_req(card->host);
-		return 0;
-	}
+	msb->transfer_cmd = is_read ?
+				MSPRO_CMD_READ_DATA :MSPRO_CMD_WRITE_DATA;
 
-	dev_dbg(&card->dev, "blk_fetch\n");
-	msb->block_req = blk_fetch_request(msb->queue);
-	if (!msb->block_req) {
-		dev_dbg(&card->dev, "issue end\n");
-		return -EAGAIN;
-	}
+	msb->arg.system = msb->system;
+	msb->arg.data_count = cpu_to_be16(pages);
+	msb->arg.data_address = cpu_to_be32(sec);
+	msb->data_dir = rq_data_dir(msb->block_req);
 
-	dev_dbg(&card->dev, "trying again\n");
-	chunk = 1;
-	goto try_again;
+	dbg(card, "IO: %s: lba %x, pages %x", is_read ? "read" : "write",
+					(unsigned int)sec, pages);
+	if (first)
+		memstick_run_state_machine(card,
+			h_mspro_block_transfer_data, false);
+	return 0;
 }
 
 /*
@@ -584,59 +628,23 @@ try_again:
  *  After execution of this function, the msb->block_req might or might not
  *  be NULL. If it is, it means we don't have any more requests to process
  */
-static int mspro_block_complete_req(struct memstick_dev *card, int error)
+static void mspro_block_complete_req(struct memstick_dev *card, int error)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	int chunk, cnt;
-	unsigned int t_len = 0;
-	unsigned long flags;
 
-	spin_lock_irqsave(&msb->q_lock, flags);
-	dev_dbg(&card->dev, "complete %d, %d\n", msb->has_request ? 1 : 0,
-		error);
-
-	if (msb->has_request) {
-		/* Nothing to do - not really an error */
-		if (error == -EAGAIN)
-			error = 0;
-
-		if (error || (card->current_mrq.tpc == MSPRO_CMD_STOP)) {
-			if (msb->data_dir == READ) {
-				for (cnt = 0; cnt < msb->current_seg; cnt++)
-					t_len += msb->req_sg[cnt].length
-						 / msb->page_size;
-
-					if (msb->current_page)
-						t_len += msb->current_page - 1;
-
-					t_len *= msb->page_size;
-			}
-		} else
-			t_len = blk_rq_bytes(msb->block_req);
-
-		dev_dbg(&card->dev, "transferred %x (%d)\n", t_len, error);
+	dbg(card, "IO: transferred %d bytes ", msb->data_transferred);
 
-		if (error && !t_len)
-			t_len = blk_rq_cur_bytes(msb->block_req);
-
-		chunk = __blk_end_request(msb->block_req, error, t_len);
-
-		error = mspro_block_issue_req(card, chunk);
-
-		if (!error)
-			goto out;
-		else
-			msb->has_request = 0;
-	} else {
-		if (!error)
-			error = -EAGAIN;
+	if (msb->data_transferred) {
+		if (!__blk_end_request(msb->block_req, 0,
+						msb->data_transferred))
+			msb->block_req = NULL;
 	}
 
-	card->next_request = h_mspro_block_default_bad;
-	complete_all(&card->mrq_complete);
-out:
-	spin_unlock_irqrestore(&msb->q_lock, flags);
-	return error;
+	if (error && msb->block_req) {
+		dbg(card, "IO: failure (%d) of transfter of one sector", error);
+		if (!__blk_end_request(msb->block_req, 0, msb->page_size))
+			msb->block_req = NULL;
+	}
 }
 
 /*
@@ -651,7 +659,7 @@ static void mspro_block_stop(struct memstick_dev *card)
 
 	while (1) {
 		spin_lock_irqsave(&msb->q_lock, flags);
-		if (!msb->has_request) {
+		if (!msb->block_req) {
 			blk_stop_queue(msb->queue);
 			rc = 1;
 		}
@@ -692,21 +700,18 @@ static void mspro_block_submit_req(struct request_queue *q)
 {
 	struct memstick_dev *card = q->queuedata;
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	struct request *req = NULL;
-
-	if (msb->has_request)
-		return;
-
-	if (msb->eject) {
-		while ((req = blk_fetch_request(q)) != NULL)
-			__blk_end_request_all(req, -ENODEV);
+	int error;
 
+	if (msb->block_req) {
+		dbg_v(card,
+			"IO: block layer submits request, while we have one");
 		return;
 	}
 
-	msb->has_request = 1;
-	if (mspro_block_issue_req(card, 0))
-		msb->has_request = 0;
+	dbg(card, "IO: block layer wakes us up for request processing");
+
+	error = mspro_block_issue_req(card, true);
+	WARN_ON(error && msb->block_req != NULL);
 }
 
 /*** Initialization ***/
@@ -820,6 +825,29 @@ try_again:
 	return rc;
 }
 
+/* Read data from attribute space */
+static int mspro_block_read_attribute(struct memstick_dev *card,
+					int offset, void *buffer, int len)
+{
+	struct mspro_block_data *msb = memstick_get_drvdata(card);
+
+	dbg(card, "reading attribute space at offset %08x, size %d",
+								offset, len);
+	sg_init_one(&msb->req_sg[0], buffer, len);
+	msb->current_sg_offset = 0;
+	msb->current_sg = msb->req_sg;
+	msb->data_transferred = 0;
+	msb->io_error = 0;
+	msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
+	msb->arg.system = msb->system;
+	msb->arg.data_count = cpu_to_be16(len / msb->page_size);
+	msb->arg.data_address = cpu_to_be32(offset / msb->page_size);
+	msb->data_dir = READ;
+
+	return memstick_run_state_machine(card,
+					h_mspro_block_transfer_data, true);
+}
+
 /* Memory allocated for attributes by this function should be freed by
  * mspro_block_data_clear, no matter if the initialization process succeded
  * or failed.
@@ -827,85 +855,71 @@ try_again:
 static int mspro_block_read_attributes(struct memstick_dev *card)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	struct mspro_param_register param = {
-		.system = msb->system,
-		.data_count = cpu_to_be16(1),
-		.data_address = 0,
-		.tpc_param = 0
-	};
 	struct mspro_attribute *attr = NULL;
 	struct mspro_sys_attr *s_attr = NULL;
+
 	unsigned char *buffer = NULL;
-	int cnt, rc, attr_count;
-	unsigned int addr;
-	unsigned short page_count;
+	unsigned int buffer_size, new_buffer_size, buffer_address = 0;
+	unsigned int attr_size, attr_addr, attr_page_offset;
 
-	attr = kmalloc(msb->page_size, GFP_KERNEL);
-	if (!attr)
+	int cnt, error, attr_count;
+
+	/* Allocate initial buffer */
+	buffer_size = msb->page_size;
+	buffer_address = 0;
+	buffer = kmalloc(buffer_size, GFP_KERNEL);
+	if (!buffer)
 		return -ENOMEM;
 
-	sg_init_one(&msb->req_sg[0], attr, msb->page_size);
-	msb->seg_count = 1;
-	msb->current_seg = 0;
-	msb->current_page = 0;
-	msb->data_dir = READ;
-	msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
+	/* Read the attribute list */
+	error = mspro_block_read_attribute(card, 0, buffer, buffer_size);
+	if (error)
+		goto out_free_buffer;
+
+	attr = kmalloc(buffer_size, GFP_KERNEL);
+	if (!attr)
+		goto out_free_buffer;
+	memcpy(attr, buffer, buffer_size);
 
-	card->next_request = h_mspro_block_req_init;
-	msb->mrq_handler = h_mspro_block_transfer_data;
-	memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, &param,
-			  sizeof(param));
-	memstick_new_req(card->host);
-	wait_for_completion(&card->mrq_complete);
-	if (card->current_mrq.error) {
-		rc = card->current_mrq.error;
-		goto out_free_attr;
-	}
 
+	/* Test it for sanity */
 	if (be16_to_cpu(attr->signature) != MSPRO_BLOCK_SIGNATURE) {
 		printk(KERN_ERR "%s: unrecognized device signature %x\n",
 		       dev_name(&card->dev), be16_to_cpu(attr->signature));
-		rc = -ENODEV;
-		goto out_free_attr;
+		error = -ENODEV;
+		goto out_free_buffer;
 	}
 
-	if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES) {
+	if (attr->count > MSPRO_BLOCK_MAX_ATTRIBUTES)
 		printk(KERN_WARNING "%s: way too many attribute entries\n",
 		       dev_name(&card->dev));
-		attr_count = MSPRO_BLOCK_MAX_ATTRIBUTES;
-	} else
-		attr_count = attr->count;
-
-	msb->attr_group.attrs = kzalloc((attr_count + 1)
-					* sizeof(struct attribute),
-					GFP_KERNEL);
-	if (!msb->attr_group.attrs) {
-		rc = -ENOMEM;
-		goto out_free_attr;
-	}
-	msb->attr_group.name = "media_attributes";
 
-	buffer = kmalloc(msb->page_size, GFP_KERNEL);
-	if (!buffer) {
-		rc = -ENOMEM;
-		goto out_free_attr;
-	}
-	memcpy(buffer, (char *)attr, msb->page_size);
-	page_count = 1;
+	attr_count = min((int)attr->count, (int)MSPRO_BLOCK_MAX_ATTRIBUTES);
+
+	/* Allocate attribute group */
+	error = -ENOMEM;
+	msb->attr_group.attrs = kzalloc((attr_count + 1) *
+					sizeof(struct attribute), GFP_KERNEL);
+	if (!msb->attr_group.attrs)
+		goto out_free_buffer;
 
+	msb->attr_group.name = "media_attributes";
+
+	/* Read all other attributes */
 	for (cnt = 0; cnt < attr_count; ++cnt) {
+
+		/* Create new sysfs attribute */
 		s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL);
-		if (!s_attr) {
-			rc = -ENOMEM;
+		error = -ENOMEM;
+		if (!s_attr)
 			goto out_free_buffer;
-		}
 
-		msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr;
-		addr = be32_to_cpu(attr->entries[cnt].address);
-		rc = be32_to_cpu(attr->entries[cnt].size);
-		dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, "
-			"size %x\n", cnt, attr->entries[cnt].id, addr, rc);
+		sysfs_attr_init(&s_attr->dev_attr.attr);
+		s_attr->dev_attr.attr.name = s_attr->name;
+		s_attr->dev_attr.attr.mode = S_IRUGO;
 		s_attr->id = attr->entries[cnt].id;
+		s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);
+
 		if (mspro_block_attr_name(s_attr->id))
 			snprintf(s_attr->name, sizeof(s_attr->name), "%s",
 				 mspro_block_attr_name(attr->entries[cnt].id));
@@ -913,78 +927,62 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
 			snprintf(s_attr->name, sizeof(s_attr->name),
 				 "attr_x%02x", attr->entries[cnt].id);
 
-		sysfs_attr_init(&s_attr->dev_attr.attr);
-		s_attr->dev_attr.attr.name = s_attr->name;
-		s_attr->dev_attr.attr.mode = S_IRUGO;
-		s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);
+		msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr;
 
-		if (!rc)
+
+		attr_addr = be32_to_cpu(attr->entries[cnt].address);
+		attr_size = be32_to_cpu(attr->entries[cnt].size);
+		attr_page_offset = attr_addr % msb->page_size;
+
+		if (!attr_size)
 			continue;
 
-		s_attr->size = rc;
-		s_attr->data = kmalloc(rc, GFP_KERNEL);
+		dbg(card, "adding attribute %d: id %x, address %x, size %x",
+			cnt, s_attr->id, attr_addr, attr_size);
+
+		s_attr->size = attr_size;
+		s_attr->data = kmalloc(attr_size, GFP_KERNEL);
 		if (!s_attr->data) {
-			rc = -ENOMEM;
+			error = -ENOMEM;
 			goto out_free_buffer;
 		}
 
-		if (((addr / msb->page_size)
-		     == be32_to_cpu(param.data_address))
-		    && (((addr + rc - 1) / msb->page_size)
-			== be32_to_cpu(param.data_address))) {
-			memcpy(s_attr->data, buffer + addr % msb->page_size,
-			       rc);
+		/* If we already read that attribute as part of last one,
+								use that */
+		if (round_down(attr_addr, msb->page_size) == buffer_address &&
+		    attr_addr + attr_size <= buffer_address + buffer_size) {
+
+			memcpy(s_attr->data, buffer + attr_page_offset,
+								attr_size);
 			continue;
 		}
 
-		if (page_count <= (rc / msb->page_size)) {
+		/* Reallocate buffer if nessesary */
+		new_buffer_size = roundup(attr_page_offset + attr_size,
+								msb->page_size);
+		buffer_address = round_down(attr_addr, msb->page_size);
+
+		if (new_buffer_size > buffer_size) {
 			kfree(buffer);
-			page_count = (rc / msb->page_size) + 1;
-			buffer = kmalloc(page_count * msb->page_size,
-					 GFP_KERNEL);
-			if (!buffer) {
-				rc = -ENOMEM;
-				goto out_free_attr;
-			}
-		}
+			buffer_size = new_buffer_size;
+			buffer = kmalloc(buffer_size, GFP_KERNEL);
+			if (!buffer)
+				goto out_free_buffer;
 
-		param.system = msb->system;
-		param.data_count = cpu_to_be16((rc / msb->page_size) + 1);
-		param.data_address = cpu_to_be32(addr / msb->page_size);
-		param.tpc_param = 0;
-
-		sg_init_one(&msb->req_sg[0], buffer,
-			    be16_to_cpu(param.data_count) * msb->page_size);
-		msb->seg_count = 1;
-		msb->current_seg = 0;
-		msb->current_page = 0;
-		msb->data_dir = READ;
-		msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
-
-		dev_dbg(&card->dev, "reading attribute pages %x, %x\n",
-			be32_to_cpu(param.data_address),
-			be16_to_cpu(param.data_count));
-
-		card->next_request = h_mspro_block_req_init;
-		msb->mrq_handler = h_mspro_block_transfer_data;
-		memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG,
-				  (char *)&param, sizeof(param));
-		memstick_new_req(card->host);
-		wait_for_completion(&card->mrq_complete);
-		if (card->current_mrq.error) {
-			rc = card->current_mrq.error;
-			goto out_free_buffer;
 		}
 
-		memcpy(s_attr->data, buffer + addr % msb->page_size, rc);
+		/* Finaly read and save the attrubute */
+		error = mspro_block_read_attribute(card,
+			buffer_address,
+			buffer, new_buffer_size);
+		memcpy(s_attr->data, buffer + attr_page_offset, attr_size);
 	}
 
-	rc = 0;
+	error = 0;
 out_free_buffer:
 	kfree(buffer);
-out_free_attr:
 	kfree(attr);
-	return rc;
+	return error;
 }
 
 static int mspro_block_init_card(struct memstick_dev *card)
diff --git a/drivers/memstick/core/mspro_block.h b/drivers/memstick/core/mspro_block.h
index afb29f8..ba9f78c 100644
--- a/drivers/memstick/core/mspro_block.h
+++ b/drivers/memstick/core/mspro_block.h
@@ -126,41 +126,44 @@ struct mspro_devinfo {
 
 
 struct mspro_block_data {
-	struct memstick_dev   *card;
-	unsigned int          usage_count;
-	unsigned int          caps;
-	struct gendisk        *disk;
-	struct request_queue  *queue;
-	struct request        *block_req;
-	spinlock_t            q_lock;
-
-	unsigned short        page_size;
-	unsigned short        cylinders;
-	unsigned short        heads;
-	unsigned short        sectors_per_track;
-
-	unsigned char         system;
-	unsigned char         read_only:1,
-			      eject:1,
-			      has_request:1,
-			      data_dir:1,
-			      active:1;
-	unsigned char         transfer_cmd;
-
-	int                   (*mrq_handler)(struct memstick_dev *card,
-					     struct memstick_request **mrq);
-
-	struct attribute_group attr_group;
-
-	struct scatterlist    req_sg[MSPRO_BLOCK_MAX_SEGS];
-	unsigned int          seg_count;
-	unsigned int          current_seg;
-	unsigned int          current_page;
+	struct memstick_dev              *card;
+	unsigned int                     usage_count;
+	unsigned int                     caps;
+	struct gendisk                   *disk;
+	struct request_queue             *queue;
+	struct request                   *block_req;
+	spinlock_t                       q_lock;
+	struct scatterlist               req_sg[MSPRO_BLOCK_MAX_SEGS];
+
+	int                           (*mrq_handler)(struct memstick_dev *card,
+						struct memstick_request **mrq);
+
+	unsigned char                    read_only:1;
+	unsigned char                    eject:1;
+	unsigned char                    active:1;
+
+	/* Media info */
+	struct attribute_group           attr_group;
+	unsigned short                   page_size;
+	unsigned short                   cylinders;
+	unsigned short                   heads;
+	unsigned short                   sectors_per_track;
+
+	/* Handlers state */
+	unsigned char                    system;
+	unsigned char                    transfer_cmd;
+	struct mspro_param_register      arg;
+
+	struct scatterlist               *current_sg;
+	unsigned int                     current_sg_offset;
+	unsigned int	                 data_transferred;
+	unsigned char                    data_dir:1;
+	int                              io_error;
 };
 
-static int mspro_block_complete_req(struct memstick_dev *card, int error);
+static void mspro_block_complete_req(struct memstick_dev *card, int error);
 static int mspro_block_switch_interface(struct memstick_dev *card);
-static int mspro_block_issue_req(struct memstick_dev *card, int chunk);
+static int mspro_block_issue_req(struct memstick_dev *card, bool first);
 
 #define __dbg(card, level, format, ...) \
 	do { \
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 10/29] memstick: mspro: create _setup_io helper.
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (8 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 09/29] memstick: rework state machines + attribute read function Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:25   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD Maxim Levitsky
                   ` (19 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

This function contains common parts of IO setup
for the state machine, thus reduces the risk
of using the state machine in wrong way.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/mspro_block.c |   46 ++++++++++++++++++----------------
 1 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index cf98fa8..0d8b30b 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -561,6 +561,26 @@ again:
 
 /*** Data transfer ***/
 
+/* Common helper that prepares state for IO (read, write, read attributes) */
+static int mspro_block_setup_io(struct memstick_dev *card, int direction,
+				int sector, int pages, unsigned char command)
+{
+	struct mspro_block_data *msb = memstick_get_drvdata(card);
+
+	msb->current_sg_offset = 0;
+	msb->current_sg = msb->req_sg;
+	msb->data_transferred = 0;
+	msb->io_error = 0;
+
+	msb->transfer_cmd = command;
+
+	msb->arg.system = msb->system;
+	msb->arg.data_count = cpu_to_be16(pages);
+	msb->arg.data_address = cpu_to_be32(sector);
+	msb->data_dir = direction;
+	return 0;
+}
+
 /*
  * Start execution of next block request,
  * or continue execution of the current one
@@ -602,18 +622,8 @@ again:
 
 	is_read = rq_data_dir(msb->block_req) == READ;
 
-	msb->current_sg_offset = 0;
-	msb->current_sg = msb->req_sg;
-	msb->data_transferred = 0;
-	msb->io_error = 0;
-
-	msb->transfer_cmd = is_read ?
-				MSPRO_CMD_READ_DATA :MSPRO_CMD_WRITE_DATA;
-
-	msb->arg.system = msb->system;
-	msb->arg.data_count = cpu_to_be16(pages);
-	msb->arg.data_address = cpu_to_be32(sec);
-	msb->data_dir = rq_data_dir(msb->block_req);
+	mspro_block_setup_io(card, rq_data_dir(msb->block_req), sec, pages,
+		is_read ? MSPRO_CMD_READ_DATA : MSPRO_CMD_WRITE_DATA);
 
 	dbg(card, "IO: %s: lba %x, pages %x", is_read ? "read" : "write",
 					(unsigned int)sec, pages);
@@ -834,16 +844,8 @@ static int mspro_block_read_attribute(struct memstick_dev *card,
 	dbg(card, "reading attribute space at offset %08x, size %d",
 								offset, len);
 	sg_init_one(&msb->req_sg[0], buffer, len);
-	msb->current_sg_offset = 0;
-	msb->current_sg = msb->req_sg;
-	msb->data_transferred = 0;
-	msb->io_error = 0;
-	msb->transfer_cmd = MSPRO_CMD_READ_ATRB;
-	msb->arg.system = msb->system;
-	msb->arg.data_count = cpu_to_be16(len / msb->page_size);
-	msb->arg.data_address = cpu_to_be32(offset / msb->page_size);
-	msb->data_dir = READ;
-
+	mspro_block_setup_io(card, READ, offset / msb->page_size,
+				len / msb->page_size, MSPRO_CMD_READ_ATRB);
 	return memstick_run_state_machine(card,
 					h_mspro_block_transfer_data, true);
 }
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (9 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 10/29] memstick: mspro: create _setup_io helper Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:27   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 12/29] memstick: mspro: rework interface switch Maxim Levitsky
                   ` (18 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

This little optimization done by Sony for
PRO variant of the cards allows to bundle the param register
with the command and therefore send one TPC less.

This increases IO throughput somewhat.
(4.4 -> 4.8 MB/s on Jmicron for example)

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/mspro_block.c |   35 +++++++++++++----------------------
 drivers/memstick/core/mspro_block.h |    3 +--
 2 files changed, 14 insertions(+), 24 deletions(-)

diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 0d8b30b..e54d467 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -438,35 +438,28 @@ static int h_mspro_block_transfer_data(struct memstick_dev *card,
 
 		if (!msb->io_error) {
 			msb->io_error = (*mrq)->error;
-			card->state = 6;
+			card->state = 5;
 		}
 	}
 again:
 	switch (card->state) {
 
 	case 0: /* send read/write command + args */
-		if (!memstick_write_regs(card,
-			offsetof(struct mspro_register, param),
-			sizeof(struct mspro_param_register),
-			(unsigned char *)&msb->arg, *mrq))
-			return 0;
-		break;
-	case 1:
-		memstick_init_req(*mrq, MS_TPC_SET_CMD,
-					&msb->transfer_cmd, 1);
+		memstick_init_req(*mrq, MS_TPC_EX_SET_CMD,
+					&msb->arg, sizeof(msb->arg));
 		break;
 
-	case 2: /* read the INT register */
+	case 1: /* read the INT register */
 		if (memstick_read_int_reg(card, *mrq, -1))
 			break;
 		card->state++;
 
-	case 3: /* process the int register */
+	case 2: /* process the int register */
 		intreg = (*mrq)->data[0];
 
 		if (intreg & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) {
 			dbg(card, "IO: card I/O error");
-			card->state = 6;
+			card->state = 5;
 			msb->io_error = -EIO;
 			goto again;
 		}
@@ -479,7 +472,7 @@ again:
 			}
 
 			memstick_read_int_reg_cleanup(card);
-			card->state = 7;
+			card->state = 6;
 			goto again;
 		}
 
@@ -492,7 +485,7 @@ again:
 		memstick_read_int_reg_cleanup(card);
 		card->state++;
 
-	case 4: /* init transfer of the data */
+	case 3: /* init transfer of the data */
 		t_offset = msb->current_sg->offset + msb->current_sg_offset;
 
 		sg_init_table(&t_sg, 1);
@@ -505,7 +498,7 @@ again:
 		(*mrq)->need_card_int = 1;
 		break;
 
-	case 5: /* switch to next page */
+	case 4: /* switch to next page */
 		msb->current_sg_offset += msb->page_size;
 		msb->data_transferred += msb->page_size;
 
@@ -514,15 +507,15 @@ again:
 			msb->current_sg = sg_next(msb->current_sg);
 		}
 
-		card->state = 2;
+		card->state = 1;
 		goto again;
 
-	case 6: /* after a error send STOP command */
+	case 5: /* after a error send STOP command */
 		command = MSPRO_CMD_STOP;
 		memstick_init_req(*mrq, MS_TPC_SET_CMD, &command, 1);
 		break;
 
-	case 7: /* request complete - get next one*/
+	case 6: /* request complete - get next one*/
 		spin_lock_irqsave(&msb->q_lock, flags);
 
 		if (msb->io_error)
@@ -572,9 +565,7 @@ static int mspro_block_setup_io(struct memstick_dev *card, int direction,
 	msb->data_transferred = 0;
 	msb->io_error = 0;
 
-	msb->transfer_cmd = command;
-
-	msb->arg.system = msb->system;
+	msb->arg.command = command;
 	msb->arg.data_count = cpu_to_be16(pages);
 	msb->arg.data_address = cpu_to_be32(sector);
 	msb->data_dir = direction;
diff --git a/drivers/memstick/core/mspro_block.h b/drivers/memstick/core/mspro_block.h
index ba9f78c..82ae2fe 100644
--- a/drivers/memstick/core/mspro_block.h
+++ b/drivers/memstick/core/mspro_block.h
@@ -151,8 +151,7 @@ struct mspro_block_data {
 
 	/* Handlers state */
 	unsigned char                    system;
-	unsigned char                    transfer_cmd;
-	struct mspro_param_register      arg;
+	struct mspro_cmdex_argument      arg;
 
 	struct scatterlist               *current_sg;
 	unsigned int                     current_sg_offset;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 12/29] memstick: mspro: rework interface switch
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (10 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:28   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq Maxim Levitsky
                   ` (17 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Now no old style state machine exist.
Thus this patch removes now unused code.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/memstick.c    |   15 --
 drivers/memstick/core/mspro_block.c |  328 +++++++++++++++++------------------
 drivers/memstick/core/mspro_block.h |    4 +-
 include/linux/memstick.h            |    2 -
 4 files changed, 162 insertions(+), 187 deletions(-)

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index e1aa089..5eea1b2 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -424,21 +424,6 @@ int memstick_set_rw_addr(struct memstick_dev *card)
 EXPORT_SYMBOL(memstick_set_rw_addr);
 
 
-/**
- * memstick_new_req - notify the host that some requests are pending
- * @host - host to use
- */
-void memstick_new_req(struct memstick_host *host)
-{
-	if (host->card) {
-		host->retries = cmd_retries;
-		INIT_COMPLETION(host->card->mrq_complete);
-		host->request(host);
-	}
-}
-EXPORT_SYMBOL(memstick_new_req);
-
-
 /*** state machine support code ***/
 
 /**
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index e54d467..85018ce 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -372,54 +372,6 @@ static sysfs_show_t mspro_block_attr_show(unsigned char tag)
  * finished (and request processor should come back some time later).
  */
 
-static int h_mspro_block_req_init(struct memstick_dev *card,
-				  struct memstick_request **mrq)
-{
-	struct mspro_block_data *msb = memstick_get_drvdata(card);
-
-	*mrq = &card->current_mrq;
-	card->next_request = msb->mrq_handler;
-	return 0;
-}
-
-static int h_mspro_block_default(struct memstick_dev *card,
-				 struct memstick_request **mrq)
-{
-	return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
-}
-
-
-static int h_mspro_block_get_ro(struct memstick_dev *card,
-				struct memstick_request **mrq)
-{
-	struct mspro_block_data *msb = memstick_get_drvdata(card);
-
-	if (!(*mrq)->error) {
-		if ((*mrq)->data[offsetof(struct ms_status_register, status0)]
-		    & MEMSTICK_STATUS0_WP)
-			msb->read_only = 1;
-		else
-			msb->read_only = 0;
-	}
-
-	return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
-}
-
-static int h_mspro_block_wait_for_ced(struct memstick_dev *card,
-				      struct memstick_request **mrq)
-{
-	dev_dbg(&card->dev, "wait for ced: value %x\n", (*mrq)->data[0]);
-
-	if (!(*mrq)->error) {
-		if ((*mrq)->data[0] & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR))
-			(*mrq)->error = -EFAULT;
-		else if (!((*mrq)->data[0] & MEMSTICK_INT_CED))
-			return 0;
-	}
-
-	return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
-}
-
 static int h_mspro_block_transfer_data(struct memstick_dev *card,
 				       struct memstick_request **mrq)
 {
@@ -552,6 +504,109 @@ again:
 	return 0;
 }
 
+
+static int h_mspro_block_reset(struct memstick_dev *card,
+					struct memstick_request **mrq)
+{
+	struct mspro_block_data *msb = memstick_get_drvdata(card);
+	struct ms_status_register *status;
+	u8 intreg;
+
+	memstick_allocate_request(card, mrq);
+	if ((*mrq)->error)
+		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+
+again:
+	switch (card->state) {
+
+	case 0: /* send request for INT reg */
+		if (memstick_read_int_reg(card, *mrq, 10000))
+			break;
+		card->state++;
+
+	case 1: /* process the INT reg and loop if nessesary */
+		intreg = (*mrq)->data[0];
+
+		if (intreg & MEMSTICK_INT_ERR) {
+			if ((intreg & MEMSTICK_INT_CMDNAK)) {
+				msb->read_only = true;
+				return memstick_exit_state_machine(card,
+								*mrq, 0);
+			}
+			return memstick_exit_state_machine(card, *mrq, -EIO);
+		}
+
+		if (intreg & MEMSTICK_INT_CMDNAK)
+			return memstick_exit_state_machine(card, *mrq, -EIO);
+
+
+		if (!(intreg & MEMSTICK_INT_CED)) {
+			card->state--;
+			goto again;
+		}
+
+		memstick_read_int_reg_cleanup(card);
+		card->state++;
+
+	case 2: /* read the R/O status */
+
+		if (!memstick_read_regs(card,
+			offsetof(struct mspro_register, status),
+			sizeof(struct ms_status_register),
+			*mrq))
+			return 0;
+		break;
+
+	case 3: /* process the result & done */
+		status = (struct ms_status_register *)(*mrq)->data;
+		msb->read_only = status->status0 & MEMSTICK_STATUS0_WP;
+		return memstick_exit_state_machine(card, *mrq, 0);
+	}
+
+	card->state++;
+	return 0;
+
+}
+
+static int h_mspro_block_switch_interface(struct memstick_dev *card,
+					struct memstick_request **mrq)
+{
+	struct mspro_block_data *msb = memstick_get_drvdata(card);
+	int error;
+	memstick_allocate_request(card, mrq);
+	if ((*mrq)->error)
+		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+
+	switch (card->state) {
+
+	case 0: /* send switch command to the device */
+		if (!memstick_write_regs(card,
+			offsetof(struct mspro_register, param),
+			1,
+			&msb->system,
+			*mrq))
+			return 0;
+		break;
+
+	case 1: /* switch the host intrface + send dummy read to verify that */
+		/* connection works */
+		error = card->host->set_param(card->host,
+				MEMSTICK_INTERFACE, msb->target_interface);
+		if (error)
+			return memstick_exit_state_machine(card, *mrq, -EFAULT);
+
+		memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);
+		break;
+
+	case 2: /* done */
+		return memstick_exit_state_machine(card, *mrq, 0);
+
+	}
+
+	card->state++;
+	return 0;
+}
+
 /*** Data transfer ***/
 
 /* Common helper that prepares state for IO (read, write, read attributes) */
@@ -717,113 +772,77 @@ static void mspro_block_submit_req(struct request_queue *q)
 
 /*** Initialization ***/
 
-static int mspro_block_wait_for_ced(struct memstick_dev *card)
+/* Reset the card */
+static int mspro_block_reset(struct memstick_dev *card, bool full)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
+	int error;
 
-	card->next_request = h_mspro_block_req_init;
-	msb->mrq_handler = h_mspro_block_wait_for_ced;
-	memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1);
-	memstick_new_req(card->host);
-	wait_for_completion(&card->mrq_complete);
-	return card->current_mrq.error;
-}
+	dbg(card, "resetting the card");
 
-static int mspro_block_set_interface(struct memstick_dev *card,
-				     unsigned char sys_reg)
-{
-	struct memstick_host *host = card->host;
-	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	struct mspro_param_register param = {
-		.system = sys_reg,
-		.data_count = 0,
-		.data_address = 0,
-		.tpc_param = 0
-	};
+	msb->system = MEMSTICK_SYS_SERIAL;
 
-	card->next_request = h_mspro_block_req_init;
-	msb->mrq_handler = h_mspro_block_default;
-	memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, &param,
-			  sizeof(param));
-	memstick_new_req(host);
-	wait_for_completion(&card->mrq_complete);
-	return card->current_mrq.error;
+	if (full) {
+		error = memstick_reset(card->host);
+		if (error) {
+			dbg(card, "host controller reset failure");
+			return error;
+		}
+	}
+
+	msleep(150);
+
+	error = memstick_run_state_machine(card, h_mspro_block_reset, true);
+	if (error) {
+		dbg(card, "card reset failure");
+		return error;
+	}
+
+	return mspro_block_switch_interface(card);
 }
 
+/*
+ * Attempts to switch to faster interface.
+ * If switch fails it clears the card capability of this mode
+ * and calls reset which might call this function again but that
+ * time it won't attempt failed mode
+ */
 static int mspro_block_switch_interface(struct memstick_dev *card)
 {
 	struct memstick_host *host = card->host;
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	int rc = 0;
+	int error = 0;
 
-try_again:
-	if (msb->caps & MEMSTICK_CAP_PAR4)
-		rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR4);
-	else
+	if (!(card->caps & host->caps & MEMSTICK_CAP_PAR4))
 		return 0;
 
-	if (rc) {
-		printk(KERN_WARNING
-		       "%s: could not switch to 4-bit mode, error %d\n",
-		       dev_name(&card->dev), rc);
-		return 0;
-	}
+	dbg(card, "switching to parallel 4 bit inteface");
 
 	msb->system = MEMSTICK_SYS_PAR4;
-	host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4);
-	printk(KERN_INFO "%s: switching to 4-bit parallel mode\n",
-	       dev_name(&card->dev));
-
-	if (msb->caps & MEMSTICK_CAP_PAR8) {
-		rc = mspro_block_set_interface(card, MEMSTICK_SYS_PAR8);
-
-		if (!rc) {
-			msb->system = MEMSTICK_SYS_PAR8;
-			host->set_param(host, MEMSTICK_INTERFACE,
-					MEMSTICK_PAR8);
-			printk(KERN_INFO
-			       "%s: switching to 8-bit parallel mode\n",
-			       dev_name(&card->dev));
-		} else
-			printk(KERN_WARNING
-			       "%s: could not switch to 8-bit mode, error %d\n",
-			       dev_name(&card->dev), rc);
+	msb->target_interface = MEMSTICK_PAR4;
+	error = memstick_run_state_machine(card,
+				h_mspro_block_switch_interface, true);
+	if (error) {
+		dbg(card, "failure to switch to parallel 4 bit inteface");
+		card->caps &= ~MEMSTICK_CAP_PAR4;
+		return mspro_block_reset(card, true);
 	}
 
-	card->next_request = h_mspro_block_req_init;
-	msb->mrq_handler = h_mspro_block_default;
-	memstick_init_req(&card->current_mrq, MS_TPC_GET_INT, NULL, 1);
-	memstick_new_req(card->host);
-	wait_for_completion(&card->mrq_complete);
-	rc = card->current_mrq.error;
+	if (!(card->caps & host->caps & MEMSTICK_CAP_PAR8))
+		return 0;
 
-	if (rc) {
-		printk(KERN_WARNING
-		       "%s: interface error, trying to fall back to serial\n",
-		       dev_name(&card->dev));
-		msb->system = MEMSTICK_SYS_SERIAL;
-		host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
-		msleep(10);
-		host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_ON);
-		host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_SERIAL);
-
-		rc = memstick_set_rw_addr(card);
-		if (!rc)
-			rc = mspro_block_set_interface(card, msb->system);
-
-		if (!rc) {
-			msleep(150);
-			rc = mspro_block_wait_for_ced(card);
-			if (rc)
-				return rc;
-
-			if (msb->caps & MEMSTICK_CAP_PAR8) {
-				msb->caps &= ~MEMSTICK_CAP_PAR8;
-				goto try_again;
-			}
-		}
+	msb->system = MEMSTICK_SYS_PAR8;
+	msb->target_interface = MEMSTICK_PAR8;
+	dbg(card, "switching to parallel 8 bit inteface");
+	error = memstick_run_state_machine(card,
+					h_mspro_block_switch_interface, true);
+	if (error) {
+		dbg(card, "failure to switch to parallel 8 bit inteface");
+		card->caps &= ~MEMSTICK_CAP_PAR8;
+		return mspro_block_reset(card, true);
 	}
-	return rc;
+
+	return error;
 }
 
 /* Read data from attribute space */
@@ -857,7 +876,7 @@ static int mspro_block_read_attributes(struct memstick_dev *card)
 
 	int cnt, error, attr_count;
 
-	/* Allocate initial buffer */
+	/* Allocate cache buffer */
 	buffer_size = msb->page_size;
 	buffer_address = 0;
 	buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -981,52 +1000,27 @@ out_free_buffer:
 static int mspro_block_init_card(struct memstick_dev *card)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
-	struct memstick_host *host = card->host;
 	int rc = 0;
 
-	msb->system = MEMSTICK_SYS_SERIAL;
-	card->reg_addr.r_offset = offsetof(struct mspro_register, status);
-	card->reg_addr.r_length = sizeof(struct ms_status_register);
-	card->reg_addr.w_offset = offsetof(struct mspro_register, param);
-	card->reg_addr.w_length = sizeof(struct mspro_param_register);
-
-	if (memstick_set_rw_addr(card))
-		return -EIO;
+	card->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8;
 
-	msb->caps = host->caps;
-
-	msleep(150);
-	rc = mspro_block_wait_for_ced(card);
+	rc = mspro_block_reset(card, false);
 	if (rc)
 		return rc;
 
-	rc = mspro_block_switch_interface(card);
-	if (rc)
-		return rc;
-
-	dev_dbg(&card->dev, "card activated\n");
+	dbg(card, "card activated");
 	if (msb->system != MEMSTICK_SYS_SERIAL)
-		msb->caps |= MEMSTICK_CAP_AUTO_GET_INT;
-
-	card->next_request = h_mspro_block_req_init;
-	msb->mrq_handler = h_mspro_block_get_ro;
-	memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL,
-			  sizeof(struct ms_status_register));
-	memstick_new_req(card->host);
-	wait_for_completion(&card->mrq_complete);
-	if (card->current_mrq.error)
-		return card->current_mrq.error;
+		card->caps |= MEMSTICK_CAP_AUTO_GET_INT;
 
-	dev_dbg(&card->dev, "card r/w status %d\n", msb->read_only ? 0 : 1);
+	dbg(card, "card r/w status %d", msb->read_only ? 0 : 1);
 
 	msb->page_size = 512;
 	rc = mspro_block_read_attributes(card);
 	if (rc)
 		return rc;
 
-	dev_dbg(&card->dev, "attributes loaded\n");
+	dbg(card, "attributes loaded");
 	return 0;
-
 }
 
 static int mspro_block_init_disk(struct memstick_dev *card)
diff --git a/drivers/memstick/core/mspro_block.h b/drivers/memstick/core/mspro_block.h
index 82ae2fe..a7ba42d 100644
--- a/drivers/memstick/core/mspro_block.h
+++ b/drivers/memstick/core/mspro_block.h
@@ -135,9 +135,6 @@ struct mspro_block_data {
 	spinlock_t                       q_lock;
 	struct scatterlist               req_sg[MSPRO_BLOCK_MAX_SEGS];
 
-	int                           (*mrq_handler)(struct memstick_dev *card,
-						struct memstick_request **mrq);
-
 	unsigned char                    read_only:1;
 	unsigned char                    eject:1;
 	unsigned char                    active:1;
@@ -157,6 +154,7 @@ struct mspro_block_data {
 	unsigned int                     current_sg_offset;
 	unsigned int	                 data_transferred;
 	unsigned char                    data_dir:1;
+	unsigned int                     target_interface;
 	int                              io_error;
 };
 
diff --git a/include/linux/memstick.h b/include/linux/memstick.h
index 73586cb..4700543 100644
--- a/include/linux/memstick.h
+++ b/include/linux/memstick.h
@@ -366,8 +366,6 @@ int memstick_exit_state_machine(struct memstick_dev *card,
 void memstick_allocate_request(struct memstick_dev *card,
 					struct memstick_request **mrq);
 
-void memstick_new_req(struct memstick_host *host);
-
 void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
 			  const struct scatterlist *sg);
 void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (11 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 12/29] memstick: mspro: rework interface switch Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:41   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 14/29] memstick: remove the memstick_set_rw_addr Maxim Levitsky
                   ` (16 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

This cleans up a lot of code and makes the assumption
(*mrq == &card->current_mrq) official.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/memstick.c    |  135 +++++++++++++++--------------------
 drivers/memstick/core/mspro_block.c |  102 ++++++++++++--------------
 include/linux/memstick.h            |   26 ++-----
 3 files changed, 114 insertions(+), 149 deletions(-)

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 5eea1b2..9de64eb 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -202,7 +202,6 @@ static int memstick_dummy_check(struct memstick_dev *card)
 	return 0;
 }
 
-
 /*
  * Functions prefixed with "h_" are protocol callbacks. They can be called from
  * interrupt context. Return value of 0 means that request processing is still
@@ -210,60 +209,57 @@ static int memstick_dummy_check(struct memstick_dev *card)
  * finished (and request processor should come back some time later).
  */
 
-static int h_memstick_read_dev_id(struct memstick_dev *card,
-						struct memstick_request **mrq)
+static int h_memstick_read_dev_id(struct memstick_dev *card)
 {
 	struct ms_id_register id_reg;
+	struct memstick_request *mrq = &card->current_mrq;
 
-	memstick_allocate_request(card, mrq);
-	if ((*mrq)->error)
-		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+	if (mrq->error)
+		return memstick_exit_state_machine(card, mrq->error);
 
 	switch (card->state) {
 	case 0:
 		if (!memstick_read_regs(card,
 			offsetof(struct ms_register, id),
-			sizeof(struct ms_id_register), *mrq))
+			sizeof(struct ms_id_register)))
 			return 0;
 		break;
 	case 1:
-		memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
+		memcpy(&id_reg, mrq->data, sizeof(id_reg));
 		card->id.match_flags = MEMSTICK_MATCH_ALL;
 		card->id.type = id_reg.type;
 		card->id.category = id_reg.category;
 		card->id.class = id_reg.class;
 		dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode);
-		return memstick_exit_state_machine(card, *mrq, 0);
+		return memstick_exit_state_machine(card, 0);
 	}
 
 	card->state++;
 	return 0;
 }
 
-static int h_memstick_set_rw_addr(struct memstick_dev *card,
-				  struct memstick_request **mrq)
+static int h_memstick_set_rw_addr(struct memstick_dev *card)
 {
-	memstick_allocate_request(card, mrq);
-	if ((*mrq)->error)
-		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+	struct memstick_request *mrq = &card->current_mrq;
+
+	if (mrq->error)
+		return memstick_exit_state_machine(card, mrq->error);
 
 	switch (card->state) {
 	case 0:
-		memstick_init_req(*mrq, MS_TPC_SET_RW_REG_ADRS,
+		memstick_init_req(card, MS_TPC_SET_RW_REG_ADRS,
 				  (char *)&card->reg_addr,
 				  sizeof(card->reg_addr));
 		break;
 	case 1:
-		return memstick_exit_state_machine(card, *mrq, 0);
+		return memstick_exit_state_machine(card, 0);
 	}
 
 	card->state++;
 	return 0;
 }
 
-
-static int h_memstick_default_bad(struct memstick_dev *card,
-				     struct memstick_request **mrq)
+static int h_memstick_default_bad(struct memstick_dev *card)
 {
 	return -ENXIO;
 }
@@ -273,7 +269,6 @@ static void memstick_invalidate_reg_window(struct memstick_dev *card)
 	memset(&card->reg_addr, 0, sizeof(card->reg_addr));
 }
 
-
 static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
 {
 	struct memstick_dev *card = kzalloc(sizeof(struct memstick_dev),
@@ -436,8 +431,7 @@ EXPORT_SYMBOL(memstick_set_rw_addr);
  * memstick_exit_state_machine
  */
 int memstick_run_state_machine(struct memstick_dev *card,
-	int   (*state_func)(struct memstick_dev *card,
-			struct memstick_request **mrq), bool sync)
+	int   (*state_func)(struct memstick_dev *card), bool sync)
 {
 	WARN_ON(card->state != -1);
 
@@ -472,9 +466,10 @@ EXPORT_SYMBOL(memstick_run_state_machine);
  *
  * State machines call this to signal quit
  */
-int memstick_exit_state_machine(struct memstick_dev *card,
-			struct memstick_request *req, int error)
+int memstick_exit_state_machine(struct memstick_dev *card, int error)
 {
+	WARN_ON(card->state == -1);
+
 	card->state = -1;
 	card->exit_error = error;
 	card->next_request = h_memstick_default_bad;
@@ -488,24 +483,7 @@ int memstick_exit_state_machine(struct memstick_dev *card,
 }
 EXPORT_SYMBOL(memstick_exit_state_machine);
 
-/**
- * memstick_allocate_request - create new request for use in request handler
- * @card - card to use
- * @mrq - request to initialize
- */
-void memstick_allocate_request(struct memstick_dev *card,
-					struct memstick_request **mrq)
-{
-	if (*mrq == NULL) {
-		*mrq = &card->current_mrq;
-		(*mrq)->error = 0;
-		(*mrq)->need_card_int = 0;
-		card->int_polling = false;
-		card->state = 0;
-	}
-}
-EXPORT_SYMBOL(memstick_allocate_request);
-
+/*** functions to be called by state machines ***/
 
 /**
  * memstick_init_req_sg - set request fields needed for bulk data transfer
@@ -513,9 +491,12 @@ EXPORT_SYMBOL(memstick_allocate_request);
  * @tpc - memstick Transport Protocol Command
  * @sg - TPC argument
  */
-void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
+void memstick_init_req_sg(struct memstick_dev *card, unsigned char tpc,
 			  const struct scatterlist *sg)
 {
+	struct memstick_request *mrq = &card->current_mrq;
+	WARN_ON(card->state == -1);
+
 	mrq->tpc = tpc;
 	if (tpc & 8)
 		mrq->data_dir = WRITE;
@@ -529,6 +510,10 @@ void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
 		mrq->need_card_int = 1;
 	else
 		mrq->need_card_int = 0;
+
+	if (tpc != MS_TPC_GET_INT)
+		card->int_polling = false;
+
 }
 EXPORT_SYMBOL(memstick_init_req_sg);
 
@@ -543,9 +528,12 @@ EXPORT_SYMBOL(memstick_init_req_sg);
  * in size) allows us to just copy the value between request structure and
  * user supplied buffer.
  */
-void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
+void memstick_init_req(struct memstick_dev *card, unsigned char tpc,
 		       const void *buf, size_t length)
 {
+	struct memstick_request *mrq = &card->current_mrq;
+	WARN_ON(card->state == -1);
+
 	mrq->tpc = tpc;
 	if (tpc & 8)
 		mrq->data_dir = WRITE;
@@ -562,6 +550,10 @@ void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
 		mrq->need_card_int = 1;
 	else
 		mrq->need_card_int = 0;
+
+	if (tpc != MS_TPC_GET_INT)
+		card->int_polling = false;
+
 }
 EXPORT_SYMBOL(memstick_init_req);
 
@@ -575,27 +567,28 @@ EXPORT_SYMBOL(memstick_init_req);
  * @card - card to use
  * @timeout - the timeout. if -1, then uses default
  */
-int memstick_read_int_reg(struct memstick_dev *card,
-				struct memstick_request *req, long timeout)
+
+int memstick_read_int_reg(struct memstick_dev *card, long timeout)
 {
+	struct memstick_request *mrq = &card->current_mrq;
+	WARN_ON(card->state == -1);
 
 	if (!card->int_polling) {
 		card->int_timeout = jiffies +
 			msecs_to_jiffies(timeout == -1 ? 500 : timeout);
 		card->int_polling = true;
 	} else if (time_after(jiffies, card->int_timeout)) {
-		req->data[0] = MEMSTICK_INT_CMDNAK;
+		mrq->data[0] = MEMSTICK_INT_CMDNAK;
 		return 0;
 	}
 
 	if (((card->caps | card->host->caps) & MEMSTICK_CAP_AUTO_GET_INT) &&
-							req->need_card_int) {
-		BUG_ON(req->error);
-		req->data[0] = req->int_reg;
-		req->need_card_int = 0;
+				mrq->need_card_int && !mrq->error) {
+		mrq->data[0] = mrq->int_reg;
+		mrq->need_card_int = false;
 		return 0;
 	} else {
-		memstick_init_req(req, MS_TPC_GET_INT, NULL, 1);
+		memstick_init_req(card, MS_TPC_GET_INT, NULL, 1);
 		return 1;
 	}
 }
@@ -603,19 +596,6 @@ EXPORT_SYMBOL(memstick_read_int_reg);
 
 
 /**
- * memstick_read_int_reg_cleanup - cleanup after series of calls to
- * memstick_read_int_reg. Used to cancel timeout.
- * Use this if you use memstick_read_int_reg
- * @card - card to use
- */
-void memstick_read_int_reg_cleanup(struct memstick_dev *card)
-{
-	card->int_polling = false;
-}
-EXPORT_SYMBOL(memstick_read_int_reg_cleanup);
-
-
-/**
  * memstick_read_regs - read the ms registers
  * If there is need to change the R/W window,
  * it will create the MS_TPC_SET_RW_REG_ADRS request and return 0,
@@ -626,9 +606,10 @@ EXPORT_SYMBOL(memstick_read_int_reg_cleanup);
  * @req - request to use
  */
 
-int memstick_read_regs(struct memstick_dev *card, int offset, int len,
-	struct memstick_request *req)
+int memstick_read_regs(struct memstick_dev *card, int offset, int len)
 {
+	WARN_ON(card->state == -1);
+
 	if (card->reg_addr.r_offset != offset ||
 					card->reg_addr.r_length != len) {
 		card->reg_addr.r_offset = offset;
@@ -642,12 +623,12 @@ int memstick_read_regs(struct memstick_dev *card, int offset, int len,
 			card->reg_addr.w_length = sizeof(struct ms_id_register);
 		}
 
-		memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
+		memstick_init_req(card, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
 			sizeof(card->reg_addr));
 		return 0;
 	}
 
-	memstick_init_req(req, MS_TPC_READ_REG, NULL, len);
+	memstick_init_req(card, MS_TPC_READ_REG, NULL, len);
 	return 1;
 }
 EXPORT_SYMBOL(memstick_read_regs);
@@ -664,8 +645,10 @@ EXPORT_SYMBOL(memstick_read_regs);
  * @req - request to use
  */
 int memstick_write_regs(struct memstick_dev *card, int offset, int len,
-	char *buf, struct memstick_request *req)
+	char *buf)
 {
+	WARN_ON(card->state == -1);
+
 	if (card->reg_addr.w_offset != offset ||
 					card->reg_addr.w_length != len) {
 		card->reg_addr.w_offset = offset;
@@ -676,16 +659,15 @@ int memstick_write_regs(struct memstick_dev *card, int offset, int len,
 		if (!card->reg_addr.r_length) {
 			card->reg_addr.r_offset =
 					offsetof(struct ms_register, id);
-
 			card->reg_addr.r_length = sizeof(struct ms_id_register);
 		}
 
-		memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
+		memstick_init_req(card, MS_TPC_SET_RW_REG_ADRS, &card->reg_addr,
 			sizeof(card->reg_addr));
 		return 0;
 	}
 
-	memstick_init_req(req, MS_TPC_WRITE_REG, buf, len);
+	memstick_init_req(card, MS_TPC_WRITE_REG, buf, len);
 	return 1;
 }
 EXPORT_SYMBOL(memstick_write_regs);
@@ -885,11 +867,12 @@ int memstick_next_req(struct memstick_host *host, struct memstick_request **mrq)
 	}
 
 	if (host->card && host->card->next_request)
-		rc = host->card->next_request(host->card, mrq);
+		rc = host->card->next_request(host->card);
 
-	if (!rc)
+	if (!rc) {
+		*mrq = &host->card->current_mrq;
 		host->retries = cmd_retries > 1 ? cmd_retries - 1 : 1;
-	else
+	} else
 		*mrq = NULL;
 
 	return rc;
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 85018ce..34c9334 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -372,24 +372,24 @@ static sysfs_show_t mspro_block_attr_show(unsigned char tag)
  * finished (and request processor should come back some time later).
  */
 
-static int h_mspro_block_transfer_data(struct memstick_dev *card,
-				       struct memstick_request **mrq)
+/* State machine that handles the IO. Heart of the driver */
+static int h_mspro_block_transfer_data(struct memstick_dev *card)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
+	struct memstick_request *mrq = &card->current_mrq;
+
 	unsigned char intreg = 0, command;
 	struct scatterlist t_sg = { 0 };
 	unsigned long flags;
 	int error;
 	size_t t_offset;
 
-	memstick_allocate_request(card, mrq);
-
-	if ((*mrq)->error) {
-		dbg(card, "IO: error (%d) executing %s", (*mrq)->error,
-			memstick_debug_get_tpc_name((*mrq)->tpc));
+	if (mrq->error) {
+		dbg(card, "IO: error (%d) executing %s", mrq->error,
+			memstick_debug_get_tpc_name(mrq->tpc));
 
 		if (!msb->io_error) {
-			msb->io_error = (*mrq)->error;
+			msb->io_error = mrq->error;
 			card->state = 5;
 		}
 	}
@@ -397,17 +397,17 @@ again:
 	switch (card->state) {
 
 	case 0: /* send read/write command + args */
-		memstick_init_req(*mrq, MS_TPC_EX_SET_CMD,
+		memstick_init_req(card, MS_TPC_EX_SET_CMD,
 					&msb->arg, sizeof(msb->arg));
 		break;
 
 	case 1: /* read the INT register */
-		if (memstick_read_int_reg(card, *mrq, -1))
+		if (memstick_read_int_reg(card, -1))
 			break;
 		card->state++;
 
 	case 2: /* process the int register */
-		intreg = (*mrq)->data[0];
+		intreg = mrq->data[0];
 
 		if (intreg & (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)) {
 			dbg(card, "IO: card I/O error");
@@ -423,7 +423,6 @@ again:
 				goto again;
 			}
 
-			memstick_read_int_reg_cleanup(card);
 			card->state = 6;
 			goto again;
 		}
@@ -434,7 +433,6 @@ again:
 			goto again;
 		}
 
-		memstick_read_int_reg_cleanup(card);
 		card->state++;
 
 	case 3: /* init transfer of the data */
@@ -445,9 +443,9 @@ again:
 			t_offset >> PAGE_SHIFT), msb->page_size,
 			offset_in_page(t_offset));
 
-		memstick_init_req_sg(*mrq, msb->data_dir == READ ?
+		memstick_init_req_sg(card, msb->data_dir == READ ?
 			MS_TPC_READ_LONG_DATA : MS_TPC_WRITE_LONG_DATA, &t_sg);
-		(*mrq)->need_card_int = 1;
+		mrq->need_card_int = 1;
 		break;
 
 	case 4: /* switch to next page */
@@ -464,35 +462,36 @@ again:
 
 	case 5: /* after a error send STOP command */
 		command = MSPRO_CMD_STOP;
-		memstick_init_req(*mrq, MS_TPC_SET_CMD, &command, 1);
+		memstick_init_req(card, MS_TPC_SET_CMD, &command, 1);
 		break;
 
 	case 6: /* request complete - get next one*/
 		spin_lock_irqsave(&msb->q_lock, flags);
 
 		if (msb->io_error)
-			(*mrq)->error = msb->io_error;
+			mrq->error = msb->io_error;
 
 		if (msb->block_req) {
-			mspro_block_complete_req(card, (*mrq)->error);
+			mspro_block_complete_req(card, mrq->error);
 			error = mspro_block_issue_req(card, false);
 
-			if (!msb->block_req) {
+			if (error) {
+				WARN_ON(msb->block_req);
+
 				dbg_v(card, "IO: out of requests");
 				error = memstick_exit_state_machine(
-						card, *mrq, (*mrq)->error);
+							card, mrq->error);
 				spin_unlock_irqrestore(&msb->q_lock, flags);
 				return error;
 			}
 
 			spin_unlock_irqrestore(&msb->q_lock, flags);
-			(*mrq)->error = 0;
+			mrq->error = 0;
 			card->state = 0;
 			goto again;
 
 		} else {
-			error = memstick_exit_state_machine(card,
-							*mrq, (*mrq)->error);
+			error = memstick_exit_state_machine(card, mrq->error);
 			spin_unlock_irqrestore(&msb->q_lock, flags);
 			return error;
 		}
@@ -504,40 +503,37 @@ again:
 	return 0;
 }
 
-
-static int h_mspro_block_reset(struct memstick_dev *card,
-					struct memstick_request **mrq)
+static int h_mspro_block_reset(struct memstick_dev *card)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
 	struct ms_status_register *status;
-	u8 intreg;
+	struct memstick_request *mrq = &card->current_mrq;
 
-	memstick_allocate_request(card, mrq);
-	if ((*mrq)->error)
-		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+	u8 intreg;
 
+	if (mrq->error)
+		return memstick_exit_state_machine(card, mrq->error);
 again:
 	switch (card->state) {
 
 	case 0: /* send request for INT reg */
-		if (memstick_read_int_reg(card, *mrq, 10000))
+		if (memstick_read_int_reg(card, 10000))
 			break;
 		card->state++;
 
 	case 1: /* process the INT reg and loop if nessesary */
-		intreg = (*mrq)->data[0];
+		intreg = mrq->data[0];
 
 		if (intreg & MEMSTICK_INT_ERR) {
 			if ((intreg & MEMSTICK_INT_CMDNAK)) {
 				msb->read_only = true;
-				return memstick_exit_state_machine(card,
-								*mrq, 0);
+				return memstick_exit_state_machine(card, 0);
 			}
-			return memstick_exit_state_machine(card, *mrq, -EIO);
+			return memstick_exit_state_machine(card, -EIO);
 		}
 
 		if (intreg & MEMSTICK_INT_CMDNAK)
-			return memstick_exit_state_machine(card, *mrq, -EIO);
+			return memstick_exit_state_machine(card, -EIO);
 
 
 		if (!(intreg & MEMSTICK_INT_CED)) {
@@ -545,22 +541,20 @@ again:
 			goto again;
 		}
 
-		memstick_read_int_reg_cleanup(card);
 		card->state++;
 
 	case 2: /* read the R/O status */
 
 		if (!memstick_read_regs(card,
 			offsetof(struct mspro_register, status),
-			sizeof(struct ms_status_register),
-			*mrq))
+			sizeof(struct ms_status_register)))
 			return 0;
 		break;
 
 	case 3: /* process the result & done */
-		status = (struct ms_status_register *)(*mrq)->data;
+		status = (struct ms_status_register *)mrq->data;
 		msb->read_only = status->status0 & MEMSTICK_STATUS0_WP;
-		return memstick_exit_state_machine(card, *mrq, 0);
+		return memstick_exit_state_machine(card, 0);
 	}
 
 	card->state++;
@@ -568,14 +562,14 @@ again:
 
 }
 
-static int h_mspro_block_switch_interface(struct memstick_dev *card,
-					struct memstick_request **mrq)
+static int h_mspro_block_switch_interface(struct memstick_dev *card)
 {
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
+	struct memstick_request *mrq = &card->current_mrq;
+
 	int error;
-	memstick_allocate_request(card, mrq);
-	if ((*mrq)->error)
-		return memstick_exit_state_machine(card, *mrq, (*mrq)->error);
+	if (mrq->error)
+		return memstick_exit_state_machine(card, mrq->error);
 
 	switch (card->state) {
 
@@ -583,8 +577,7 @@ static int h_mspro_block_switch_interface(struct memstick_dev *card,
 		if (!memstick_write_regs(card,
 			offsetof(struct mspro_register, param),
 			1,
-			&msb->system,
-			*mrq))
+			&msb->system))
 			return 0;
 		break;
 
@@ -593,13 +586,13 @@ static int h_mspro_block_switch_interface(struct memstick_dev *card,
 		error = card->host->set_param(card->host,
 				MEMSTICK_INTERFACE, msb->target_interface);
 		if (error)
-			return memstick_exit_state_machine(card, *mrq, -EFAULT);
+			return memstick_exit_state_machine(card, -EFAULT);
 
-		memstick_init_req(*mrq, MS_TPC_GET_INT, NULL, 1);
+		memstick_init_req(card, MS_TPC_GET_INT, NULL, 1);
 		break;
 
 	case 2: /* done */
-		return memstick_exit_state_machine(card, *mrq, 0);
+		return memstick_exit_state_machine(card, 0);
 
 	}
 
@@ -673,16 +666,15 @@ again:
 
 	dbg(card, "IO: %s: lba %x, pages %x", is_read ? "read" : "write",
 					(unsigned int)sec, pages);
+
 	if (first)
 		memstick_run_state_machine(card,
-			h_mspro_block_transfer_data, false);
+					h_mspro_block_transfer_data, false);
 	return 0;
 }
 
 /*
- * Completes execution of current block request.
- *  After execution of this function, the msb->block_req might or might not
- *  be NULL. If it is, it means we don't have any more requests to process
+ * Completes execution of current block request
  */
 static void mspro_block_complete_req(struct memstick_dev *card, int error)
 {
diff --git a/include/linux/memstick.h b/include/linux/memstick.h
index 4700543..5fd4beb 100644
--- a/include/linux/memstick.h
+++ b/include/linux/memstick.h
@@ -288,8 +288,7 @@ struct memstick_dev {
 	/* Check that media driver is still willing to operate the device. */
 	int                      (*check)(struct memstick_dev *card);
 	/* Get next request from the media driver.                         */
-	int                      (*next_request)(struct memstick_dev *card,
-						 struct memstick_request **mrq);
+	int                      (*next_request)(struct memstick_dev *card);
 	/* Tell the media driver to stop doing things                      */
 	void                     (*stop)(struct memstick_dev *card);
 	/* Allow the media driver to continue                              */
@@ -357,30 +356,21 @@ void memstick_unregister_driver(struct memstick_driver *drv);
 int memstick_set_rw_addr(struct memstick_dev *card);
 
 int memstick_run_state_machine(struct memstick_dev *card,
-	int   (*state_func)(struct memstick_dev *card,
-			struct memstick_request **mrq), bool sync);
+	int   (*state_func)(struct memstick_dev *card), bool sync);
 
-int memstick_exit_state_machine(struct memstick_dev *card,
-			struct memstick_request *req, int error);
+int memstick_exit_state_machine(struct memstick_dev *card, int error);
 
-void memstick_allocate_request(struct memstick_dev *card,
-					struct memstick_request **mrq);
-
-void memstick_init_req_sg(struct memstick_request *mrq, unsigned char tpc,
+void memstick_init_req_sg(struct memstick_dev *card, unsigned char tpc,
 			  const struct scatterlist *sg);
-void memstick_init_req(struct memstick_request *mrq, unsigned char tpc,
+void memstick_init_req(struct memstick_dev *card, unsigned char tpc,
 		       const void *buf, size_t length);
 
-int memstick_read_int_reg(struct memstick_dev *card,
-				struct memstick_request *req, long timeout);
-
-void memstick_read_int_reg_cleanup(struct memstick_dev *card);
+int memstick_read_int_reg(struct memstick_dev *card, long timeout);
 
-int memstick_read_regs(struct memstick_dev *card, int offset, int len,
-	struct memstick_request *req);
+int memstick_read_regs(struct memstick_dev *card, int offset, int len);
 
 int memstick_write_regs(struct memstick_dev *card, int offset, int len,
-	char *buf, struct memstick_request *req);
+	char *buf);
 
 const char *memstick_debug_get_tpc_name(int tpc);
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 14/29] memstick: remove the memstick_set_rw_addr
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (12 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:55   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 15/29] memstick: jmb38x_ms: Create header Maxim Levitsky
                   ` (15 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Remove this function, what was
last user that did send the MS_TPC_SET_RW_REG_ADRS
directly.

Just invalidate the register window, and next register
read/write will send that tpc automaticly.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/core/memstick.c |   49 ++++----------------------------------
 1 files changed, 5 insertions(+), 44 deletions(-)

diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 9de64eb..66fc9d6 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -238,27 +238,6 @@ static int h_memstick_read_dev_id(struct memstick_dev *card)
 	return 0;
 }
 
-static int h_memstick_set_rw_addr(struct memstick_dev *card)
-{
-	struct memstick_request *mrq = &card->current_mrq;
-
-	if (mrq->error)
-		return memstick_exit_state_machine(card, mrq->error);
-
-	switch (card->state) {
-	case 0:
-		memstick_init_req(card, MS_TPC_SET_RW_REG_ADRS,
-				  (char *)&card->reg_addr,
-				  sizeof(card->reg_addr));
-		break;
-	case 1:
-		return memstick_exit_state_machine(card, 0);
-	}
-
-	card->state++;
-	return 0;
-}
-
 static int h_memstick_default_bad(struct memstick_dev *card)
 {
 	return -ENXIO;
@@ -274,7 +253,6 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
 	struct memstick_dev *card = kzalloc(sizeof(struct memstick_dev),
 					    GFP_KERNEL);
 	struct memstick_dev *old_card = host->card;
-	struct ms_id_register id_reg;
 
 	if (card) {
 		card->host = host;
@@ -284,18 +262,12 @@ static struct memstick_dev *memstick_alloc_card(struct memstick_host *host)
 		card->dev.release = memstick_free_card;
 		card->check = memstick_dummy_check;
 
-		card->reg_addr.r_offset = offsetof(struct ms_register, id);
-		card->reg_addr.r_length = sizeof(id_reg);
-		card->reg_addr.w_offset = offsetof(struct ms_register, id);
-		card->reg_addr.w_length = sizeof(id_reg);
-
 		host->card = card;
 		init_completion(&card->mrq_complete);
 		card->state = -1;
 		card->next_request = h_memstick_default_bad;
 
-		if (memstick_set_rw_addr(card))
-			goto err_out;
+		memstick_invalidate_reg_window(card);
 
 		if (memstick_run_state_machine(card,
 						h_memstick_read_dev_id, true))
@@ -340,8 +312,10 @@ static void memstick_check(struct work_struct *work)
 	if (!host->card) {
 		if (memstick_power_on(host))
 			goto out_power_off;
-	} else if (host->card->stop)
+	} else if (host->card->stop) {
 		host->card->stop(host->card);
+		memstick_invalidate_reg_window(host->card);
+	}
 
 	card = memstick_alloc_card(host);
 
@@ -354,8 +328,7 @@ static void memstick_check(struct work_struct *work)
 		dev_dbg(&host->dev, "new card %02x, %02x, %02x\n",
 			card->id.type, card->id.category, card->id.class);
 		if (host->card) {
-			if (memstick_set_rw_addr(host->card)
-			    || !memstick_dev_match(host->card, &card->id)
+			if (!memstick_dev_match(host->card, &card->id)
 			    || !(host->card->check(host->card))) {
 				device_unregister(&host->card->dev);
 				host->card = NULL;
@@ -407,18 +380,6 @@ void memstick_unregister_driver(struct memstick_driver *drv)
 EXPORT_SYMBOL(memstick_unregister_driver);
 
 
-/**
- * memstick_set_rw_addr - issue SET_RW_REG_ADDR request and wait for it to
- *                        complete
- * @card - media device to use
- */
-int memstick_set_rw_addr(struct memstick_dev *card)
-{
-	return memstick_run_state_machine(card, h_memstick_set_rw_addr, true);
-}
-EXPORT_SYMBOL(memstick_set_rw_addr);
-
-
 /*** state machine support code ***/
 
 /**
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 15/29] memstick: jmb38x_ms: Create header
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (13 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 14/29] memstick: remove the memstick_set_rw_addr Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:56   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g Maxim Levitsky
                   ` (14 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

In the new header add:

* debug macros
* Registers + some documntation

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |  139 +--------------------------
 drivers/memstick/host/jmb38x_ms.h |  188 +++++++++++++++++++++++++++++++++++++
 2 files changed, 194 insertions(+), 133 deletions(-)
 create mode 100644 drivers/memstick/host/jmb38x_ms.h

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index f2b894c..7a00bef 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -17,141 +17,10 @@
 #include <linux/highmem.h>
 #include <linux/memstick.h>
 #include <linux/slab.h>
-
-#define DRIVER_NAME "jmb38x_ms"
+#include "jmb38x_ms.h"
 
 static int no_dma;
-module_param(no_dma, bool, 0644);
-
-enum {
-	DMA_ADDRESS       = 0x00,
-	BLOCK             = 0x04,
-	DMA_CONTROL       = 0x08,
-	TPC_P0            = 0x0c,
-	TPC_P1            = 0x10,
-	TPC               = 0x14,
-	HOST_CONTROL      = 0x18,
-	DATA              = 0x1c,
-	STATUS            = 0x20,
-	INT_STATUS        = 0x24,
-	INT_STATUS_ENABLE = 0x28,
-	INT_SIGNAL_ENABLE = 0x2c,
-	TIMER             = 0x30,
-	TIMER_CONTROL     = 0x34,
-	PAD_OUTPUT_ENABLE = 0x38,
-	PAD_PU_PD         = 0x3c,
-	CLOCK_DELAY       = 0x40,
-	ADMA_ADDRESS      = 0x44,
-	CLOCK_CONTROL     = 0x48,
-	LED_CONTROL       = 0x4c,
-	VERSION           = 0x50
-};
-
-struct jmb38x_ms_host {
-	struct jmb38x_ms        *chip;
-	void __iomem            *addr;
-	spinlock_t              lock;
-	struct tasklet_struct   notify;
-	int                     id;
-	char                    host_id[32];
-	int                     irq;
-	unsigned int            block_pos;
-	unsigned long           timeout_jiffies;
-	struct timer_list       timer;
-	struct memstick_request *req;
-	unsigned char           cmd_flags;
-	unsigned char           io_pos;
-	unsigned int            io_word[2];
-};
-
-struct jmb38x_ms {
-	struct pci_dev        *pdev;
-	int                   host_cnt;
-	struct memstick_host  *hosts[];
-};
-
-#define BLOCK_COUNT_MASK       0xffff0000
-#define BLOCK_SIZE_MASK        0x00000fff
-
-#define DMA_CONTROL_ENABLE     0x00000001
-
-#define TPC_DATA_SEL           0x00008000
-#define TPC_DIR                0x00004000
-#define TPC_WAIT_INT           0x00002000
-#define TPC_GET_INT            0x00000800
-#define TPC_CODE_SZ_MASK       0x00000700
-#define TPC_DATA_SZ_MASK       0x00000007
-
-#define HOST_CONTROL_TDELAY_EN 0x00040000
-#define HOST_CONTROL_HW_OC_P   0x00010000
-#define HOST_CONTROL_RESET_REQ 0x00008000
-#define HOST_CONTROL_REI       0x00004000
-#define HOST_CONTROL_LED       0x00000400
-#define HOST_CONTROL_FAST_CLK  0x00000200
-#define HOST_CONTROL_RESET     0x00000100
-#define HOST_CONTROL_POWER_EN  0x00000080
-#define HOST_CONTROL_CLOCK_EN  0x00000040
-#define HOST_CONTROL_REO       0x00000008
-#define HOST_CONTROL_IF_SHIFT  4
-
-#define HOST_CONTROL_IF_SERIAL 0x0
-#define HOST_CONTROL_IF_PAR4   0x1
-#define HOST_CONTROL_IF_PAR8   0x3
-
-#define STATUS_BUSY             0x00080000
-#define STATUS_MS_DAT7          0x00040000
-#define STATUS_MS_DAT6          0x00020000
-#define STATUS_MS_DAT5          0x00010000
-#define STATUS_MS_DAT4          0x00008000
-#define STATUS_MS_DAT3          0x00004000
-#define STATUS_MS_DAT2          0x00002000
-#define STATUS_MS_DAT1          0x00001000
-#define STATUS_MS_DAT0          0x00000800
-#define STATUS_HAS_MEDIA        0x00000400
-#define STATUS_FIFO_EMPTY       0x00000200
-#define STATUS_FIFO_FULL        0x00000100
-#define STATUS_MS_CED           0x00000080
-#define STATUS_MS_ERR           0x00000040
-#define STATUS_MS_BRQ           0x00000020
-#define STATUS_MS_CNK           0x00000001
-
-#define INT_STATUS_TPC_ERR      0x00080000
-#define INT_STATUS_CRC_ERR      0x00040000
-#define INT_STATUS_TIMER_TO     0x00020000
-#define INT_STATUS_HSK_TO       0x00010000
-#define INT_STATUS_ANY_ERR      0x00008000
-#define INT_STATUS_FIFO_WRDY    0x00000080
-#define INT_STATUS_FIFO_RRDY    0x00000040
-#define INT_STATUS_MEDIA_OUT    0x00000010
-#define INT_STATUS_MEDIA_IN     0x00000008
-#define INT_STATUS_DMA_BOUNDARY 0x00000004
-#define INT_STATUS_EOTRAN       0x00000002
-#define INT_STATUS_EOTPC        0x00000001
-
-#define INT_STATUS_ALL          0x000f801f
-
-#define PAD_OUTPUT_ENABLE_MS  0x0F3F
-
-#define PAD_PU_PD_OFF         0x7FFF0000
-#define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000
-#define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000
-
-#define CLOCK_CONTROL_40MHZ   0x00000001
-#define CLOCK_CONTROL_50MHZ   0x0000000a
-#define CLOCK_CONTROL_60MHZ   0x00000008
-#define CLOCK_CONTROL_62_5MHZ 0x0000000c
-#define CLOCK_CONTROL_OFF     0x00000000
-
-#define PCI_CTL_CLOCK_DLY_ADDR   0x000000b0
-#define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00
-#define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000
-
-enum {
-	CMD_READY    = 0x01,
-	FIFO_READY   = 0x02,
-	REG_DATA     = 0x04,
-	DMA_DATA     = 0x08
-};
+static int debug;
 
 static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host,
 					unsigned char *buf, unsigned int length)
@@ -1012,5 +881,9 @@ MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl);
 
+module_param(no_dma, bool, S_IRUGO);
+module_param(debug, bool, S_IRUGO);
+
+
 module_init(jmb38x_ms_init);
 module_exit(jmb38x_ms_exit);
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
new file mode 100644
index 0000000..5bca4b3
--- /dev/null
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -0,0 +1,188 @@
+/*
+ *  jmb38x_ms.c - JMicron jmb38x MemoryStick card reader
+ *
+ *  Copyright (C) 2008 Alex Dubov <oakad@yahoo.com>
+ *  Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define DRIVER_NAME "jmb38x_ms"
+
+/* physical address of a page for DMA */
+#define	DMA_ADDRESS            0x00
+
+/* controls the size of the TPC */
+#define	BLOCK                  0x04
+#define BLOCK_COUNT_MASK        0xffff0000
+#define BLOCK_COUNT_1BLOCK      0x00010000
+#define BLOCK_SIZE_MASK         0x00000fff
+
+/* Enables the DMA */
+#define	DMA_CONTROL            0x08
+#define DMA_CONTROL_ENABLE      0x00000001
+
+/* A window for small TPCs to send the contents inline */
+#define	TPC_P0                 0x0c
+#define	TPC_P1                 0x10
+
+/* TPC execution register */
+#define	TPC                    0x14
+#define TPC_DATA_SEL            0x00008000
+#define TPC_DIR                 0x00004000
+#define TPC_WAIT_INT            0x00002000
+#define TPC_GET_INT             0x00000800
+#define TPC_CODE_SZ_MASK        0x00000700
+#define TPC_DATA_SZ_MASK        0x00000007
+
+/* General device settings */
+#define	HOST_CONTROL           0x18
+#define HOST_CONTROL_TDELAY_EN  0x00040000
+#define HOST_CONTROL_HW_OC_P    0x00010000
+#define HOST_CONTROL_RESET_REQ  0x00008000
+#define HOST_CONTROL_REI        0x00004000
+#define HOST_CONTROL_LED        0x00000400
+#define HOST_CONTROL_FAST_CLK   0x00000200
+#define HOST_CONTROL_RESET      0x00000100
+#define HOST_CONTROL_POWER_EN   0x00000080
+#define HOST_CONTROL_CLOCK_EN   0x00000040
+#define HOST_CONTROL_REO        0x00000008
+#define HOST_CONTROL_BSY_TIME	0x00000007
+
+#define HOST_CONTROL_IF_SHIFT  4
+#define HOST_CONTROL_IF_SERIAL 0x0
+#define HOST_CONTROL_IF_PAR4   0x1
+#define HOST_CONTROL_IF_PAR8   0x3
+
+
+/* IO window for PIO access to internal FIFO*/
+#define	DATA                   0x1c
+
+/* MS status */
+#define	STATUS                 0x20
+#define STATUS_BUSY             0x00080000
+#define STATUS_MS_DAT7          0x00040000
+#define STATUS_MS_DAT6          0x00020000
+#define STATUS_MS_DAT5          0x00010000
+#define STATUS_MS_DAT4          0x00008000
+#define STATUS_MS_DAT3          0x00004000
+#define STATUS_MS_DAT2          0x00002000
+#define STATUS_MS_DAT1          0x00001000
+#define STATUS_MS_DAT0          0x00000800
+#define STATUS_HAS_MEDIA        0x00000400
+#define STATUS_FIFO_EMPTY       0x00000200
+#define STATUS_FIFO_FULL        0x00000100
+#define STATUS_MS_CED           0x00000080
+#define STATUS_MS_ERR           0x00000040
+#define STATUS_MS_BRQ           0x00000020
+#define STATUS_MS_CNK           0x00000001
+
+/* Device status */
+#define	INT_STATUS             0x24
+#define INT_STATUS_TPC_ERR      0x00080000
+#define INT_STATUS_CRC_ERR      0x00040000
+#define INT_STATUS_TIMER_TO     0x00020000
+#define INT_STATUS_HSK_TO       0x00010000
+#define INT_STATUS_ANY_ERR      0x00008000
+#define INT_STATUS_FIFO_WRDY    0x00000080
+#define INT_STATUS_FIFO_RRDY    0x00000040
+#define INT_STATUS_MEDIA_OUT    0x00000010
+#define INT_STATUS_MEDIA_IN     0x00000008
+#define INT_STATUS_DMA_BOUNDARY 0x00000004
+#define INT_STATUS_EOTRAN       0x00000002
+#define INT_STATUS_EOTPC        0x00000001
+#define INT_STATUS_ALL          0x000f801f
+
+/* Interrupt enable - ???*/
+#define	INT_STATUS_ENABLE      0x28
+
+/* Interrupt enable*/
+#define	INT_SIGNAL_ENABLE      0x2c
+
+/* Current timer value */
+#define	TIMER                  0x30
+
+/* Enable/disable the timer */
+#define	TIMER_CONTROL          0x34
+
+/* Output pad enable */
+#define	PAD_OUTPUT_ENABLE      0x38
+#define PAD_OUTPUT_ENABLE_MS    0x0F3F
+
+/* Ouput pad pull-up, pull-down control */
+#define	PAD_PU_PD              0x3c
+#define PAD_PU_PD_OFF           0x7fff0000
+#define PAD_PU_PD_ON_MS_SOCK0   0x5f8f0000
+#define PAD_PU_PD_ON_MS_SOCK1   0x0f0f0000
+
+/* Internal clock delay */
+#define	CLOCK_DELAY            0x40
+
+/* ??? */
+#define	ADMA_ADDRESS           0x44
+
+/* Set the device clock */
+#define	CLOCK_CONTROL          0x48
+#define CLOCK_CONTROL_RESET     0x00000008
+#define CLOCK_CONTROL_40MHZ     0x00000009
+#define CLOCK_CONTROL_50MHZ     0x0000000a
+#define CLOCK_CONTROL_62_5MHZ   0x0000000c
+#define CLOCK_CONTROL_OFF       0x00000000
+
+/* Led blink period */
+#define	LED_CONTROL            0x4c
+
+/* Hardware version */
+#define	VERSION                0x50
+
+#define PCI_CTL_CLOCK_DLY_ADDR   0x000000b0
+#define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00
+#define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000
+
+struct jmb38x_ms_host {
+	struct jmb38x_ms        *chip;
+	void __iomem            *addr;
+	spinlock_t              lock;
+	struct tasklet_struct   notify;
+	int                     id;
+	char                    host_id[32];
+	int                     irq;
+	unsigned int            block_pos;
+	unsigned long           timeout_jiffies;
+	struct timer_list       timer;
+	struct memstick_request *req;
+	unsigned char           cmd_flags;
+	unsigned char           io_pos;
+	unsigned int            io_word[2];
+};
+
+struct jmb38x_ms {
+	struct pci_dev        *pdev;
+	int                   host_cnt;
+	struct memstick_host  *hosts[];
+};
+
+enum {
+	CMD_READY    = 0x01,
+	FIFO_READY   = 0x02,
+	REG_DATA     = 0x04,
+	DMA_DATA     = 0x08
+};
+
+
+#define __dbg(host, level, format, ...) \
+	do { \
+		if (debug >= level) \
+			printk(KERN_DEBUG \
+				"%s: " format "\n", dev_name(&host->msh->dev) \
+					 , ## __VA_ARGS__); \
+		else \
+			dev_dbg(&host->msh->dev, format, ## __VA_ARGS__); \
+	} while (0)
+
+#define dbg(host, format, ...)		__dbg(host, 1, format, ## __VA_ARGS__)
+#define dbg_v(host, format, ...)	__dbg(host, 2, format, ## __VA_ARGS__)
+#define dbg_reg(host, format, ...)	__dbg(host, 3, format, ## __VA_ARGS__)
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (14 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 15/29] memstick: jmb38x_ms: Create header Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 15:58   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together Maxim Levitsky
                   ` (13 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

This just makes it easier to type function names
while still keeping the meaning
Driver name and filenames are left unchanged.


Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |  154 ++++++++++++++++++------------------
 drivers/memstick/host/jmb38x_ms.h |    6 +-
 2 files changed, 80 insertions(+), 80 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 7a00bef..e896a4d 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -22,7 +22,7 @@
 static int no_dma;
 static int debug;
 
-static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host,
+static unsigned int j38ms_read_data(struct j38ms_host *host,
 					unsigned char *buf, unsigned int length)
 {
 	unsigned int off = 0;
@@ -60,7 +60,7 @@ static unsigned int jmb38x_ms_read_data(struct jmb38x_ms_host *host,
 	return off;
 }
 
-static unsigned int jmb38x_ms_read_reg_data(struct jmb38x_ms_host *host,
+static unsigned int j38ms_read_reg_data(struct j38ms_host *host,
 					    unsigned char *buf,
 					    unsigned int length)
 {
@@ -86,7 +86,7 @@ static unsigned int jmb38x_ms_read_reg_data(struct jmb38x_ms_host *host,
 	return off;
 }
 
-static unsigned int jmb38x_ms_write_data(struct jmb38x_ms_host *host,
+static unsigned int j38ms_write_data(struct j38ms_host *host,
 					 unsigned char *buf,
 					 unsigned int length)
 {
@@ -139,7 +139,7 @@ static unsigned int jmb38x_ms_write_data(struct jmb38x_ms_host *host,
 	return off;
 }
 
-static unsigned int jmb38x_ms_write_reg_data(struct jmb38x_ms_host *host,
+static unsigned int j38ms_write_reg_data(struct j38ms_host *host,
 					     unsigned char *buf,
 					     unsigned int length)
 {
@@ -165,7 +165,7 @@ static unsigned int jmb38x_ms_write_reg_data(struct jmb38x_ms_host *host,
 	return off;
 }
 
-static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host)
+static int j38ms_transfer_data(struct j38ms_host *host)
 {
 	unsigned int length;
 	unsigned int off;
@@ -201,12 +201,12 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host)
 
 		if (host->req->data_dir == WRITE)
 			t_size = !(host->cmd_flags & REG_DATA)
-				 ? jmb38x_ms_write_data(host, buf, p_cnt)
-				 : jmb38x_ms_write_reg_data(host, buf, p_cnt);
+				 ? j38ms_write_data(host, buf, p_cnt)
+				 : j38ms_write_reg_data(host, buf, p_cnt);
 		else
 			t_size = !(host->cmd_flags & REG_DATA)
-				 ? jmb38x_ms_read_data(host, buf, p_cnt)
-				 : jmb38x_ms_read_reg_data(host, buf, p_cnt);
+				 ? j38ms_read_data(host, buf, p_cnt)
+				 : j38ms_read_reg_data(host, buf, p_cnt);
 
 		if (host->req->long_data) {
 			kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ);
@@ -232,9 +232,9 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host)
 	return length;
 }
 
-static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
+static int j38ms_issue_cmd(struct memstick_host *msh)
 {
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 	unsigned char *data;
 	unsigned int data_len, cmd, t_val;
 
@@ -313,7 +313,7 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
 		cmd |= data_len & 0xf;
 
 		if (host->req->data_dir == WRITE) {
-			jmb38x_ms_transfer_data(host);
+			j38ms_transfer_data(host);
 			writel(host->io_word[0], host->addr + TPC_P0);
 			writel(host->io_word[1], host->addr + TPC_P1);
 		}
@@ -330,9 +330,9 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh)
 	return 0;
 }
 
-static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last)
+static void j38ms_complete_cmd(struct memstick_host *msh, int last)
 {
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 	unsigned int t_val = 0;
 	int rc;
 
@@ -370,7 +370,7 @@ static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last)
 	if (!last) {
 		do {
 			rc = memstick_next_req(msh, &host->req);
-		} while (!rc && jmb38x_ms_issue_cmd(msh));
+		} while (!rc && j38ms_issue_cmd(msh));
 	} else {
 		do {
 			rc = memstick_next_req(msh, &host->req);
@@ -380,10 +380,10 @@ static void jmb38x_ms_complete_cmd(struct memstick_host *msh, int last)
 	}
 }
 
-static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id)
+static irqreturn_t j38ms_isr(int irq, void *dev_id)
 {
 	struct memstick_host *msh = dev_id;
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 	unsigned int irq_status;
 
 	spin_lock(&host->lock);
@@ -407,10 +407,10 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id)
 			} else {
 				if (irq_status & (INT_STATUS_FIFO_RRDY
 						  | INT_STATUS_FIFO_WRDY))
-					jmb38x_ms_transfer_data(host);
+					j38ms_transfer_data(host);
 
 				if (irq_status & INT_STATUS_EOTRAN) {
-					jmb38x_ms_transfer_data(host);
+					j38ms_transfer_data(host);
 					host->cmd_flags |= FIFO_READY;
 				}
 			}
@@ -427,7 +427,7 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id)
 								+ TPC_P1);
 						host->io_pos = 8;
 
-						jmb38x_ms_transfer_data(host);
+						j38ms_transfer_data(host);
 					}
 					host->cmd_flags |= FIFO_READY;
 				}
@@ -446,31 +446,31 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id)
 	    && (((host->cmd_flags & CMD_READY)
 		 && (host->cmd_flags & FIFO_READY))
 		|| host->req->error))
-		jmb38x_ms_complete_cmd(msh, 0);
+		j38ms_complete_cmd(msh, 0);
 
 	spin_unlock(&host->lock);
 	return IRQ_HANDLED;
 }
 
-static void jmb38x_ms_abort(unsigned long data)
+static void j38ms_abort(unsigned long data)
 {
 	struct memstick_host *msh = (struct memstick_host *)data;
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 	unsigned long flags;
 
 	dev_dbg(&host->chip->pdev->dev, "abort\n");
 	spin_lock_irqsave(&host->lock, flags);
 	if (host->req) {
 		host->req->error = -ETIME;
-		jmb38x_ms_complete_cmd(msh, 0);
+		j38ms_complete_cmd(msh, 0);
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void jmb38x_ms_req_tasklet(unsigned long data)
+static void j38ms_req_tasklet(unsigned long data)
 {
 	struct memstick_host *msh = (struct memstick_host *)data;
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 	unsigned long flags;
 	int rc;
 
@@ -479,24 +479,24 @@ static void jmb38x_ms_req_tasklet(unsigned long data)
 		do {
 			rc = memstick_next_req(msh, &host->req);
 			dev_dbg(&host->chip->pdev->dev, "tasklet req %d\n", rc);
-		} while (!rc && jmb38x_ms_issue_cmd(msh));
+		} while (!rc && j38ms_issue_cmd(msh));
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void jmb38x_ms_dummy_submit(struct memstick_host *msh)
+static void j38ms_dummy_submit(struct memstick_host *msh)
 {
 	return;
 }
 
-static void jmb38x_ms_submit_req(struct memstick_host *msh)
+static void j38ms_submit_req(struct memstick_host *msh)
 {
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 
 	tasklet_schedule(&host->notify);
 }
 
-static int jmb38x_ms_reset(struct jmb38x_ms_host *host)
+static int j38ms_reset(struct j38ms_host *host)
 {
 	int cnt;
 
@@ -538,11 +538,11 @@ reset_ok:
 	return 0;
 }
 
-static int jmb38x_ms_set_param(struct memstick_host *msh,
+static int j38ms_set_param(struct memstick_host *msh,
 			       enum memstick_param param,
 			       int value)
 {
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 	unsigned int host_ctl = readl(host->addr + HOST_CONTROL);
 	unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0;
 	int rc = 0;
@@ -550,7 +550,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
 	switch (param) {
 	case MEMSTICK_POWER:
 		if (value == MEMSTICK_POWER_ON) {
-			rc = jmb38x_ms_reset(host);
+			rc = j38ms_reset(host);
 			if (rc)
 				return rc;
 
@@ -623,9 +623,9 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
 
 #ifdef CONFIG_PM
 
-static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state)
+static int j38ms_suspend(struct pci_dev *dev, pm_message_t state)
 {
-	struct jmb38x_ms *jm = pci_get_drvdata(dev);
+	struct j38ms *jm = pci_get_drvdata(dev);
 	int cnt;
 
 	for (cnt = 0; cnt < jm->host_cnt; ++cnt) {
@@ -641,9 +641,9 @@ static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state)
 	return 0;
 }
 
-static int jmb38x_ms_resume(struct pci_dev *dev)
+static int j38ms_resume(struct pci_dev *dev)
 {
-	struct jmb38x_ms *jm = pci_get_drvdata(dev);
+	struct j38ms *jm = pci_get_drvdata(dev);
 	int rc;
 
 	pci_set_power_state(dev, PCI_D0);
@@ -668,12 +668,12 @@ static int jmb38x_ms_resume(struct pci_dev *dev)
 
 #else
 
-#define jmb38x_ms_suspend NULL
-#define jmb38x_ms_resume NULL
+#define j38ms_suspend NULL
+#define j38ms_resume NULL
 
 #endif /* CONFIG_PM */
 
-static int jmb38x_ms_count_slots(struct pci_dev *pdev)
+static int j38ms_count_slots(struct pci_dev *pdev)
 {
 	int cnt, rc = 0;
 
@@ -689,12 +689,12 @@ static int jmb38x_ms_count_slots(struct pci_dev *pdev)
 	return rc;
 }
 
-static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt)
+static struct memstick_host *j38ms_alloc_host(struct j38ms *jm, int cnt)
 {
 	struct memstick_host *msh;
-	struct jmb38x_ms_host *host;
+	struct j38ms_host *host;
 
-	msh = memstick_alloc_host(sizeof(struct jmb38x_ms_host),
+	msh = memstick_alloc_host(sizeof(struct j38ms_host),
 				  &jm->pdev->dev);
 	if (!msh)
 		return NULL;
@@ -713,15 +713,15 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt)
 	host->irq = jm->pdev->irq;
 	host->timeout_jiffies = msecs_to_jiffies(1000);
 
-	tasklet_init(&host->notify, jmb38x_ms_req_tasklet, (unsigned long)msh);
-	msh->request = jmb38x_ms_submit_req;
-	msh->set_param = jmb38x_ms_set_param;
+	tasklet_init(&host->notify, j38ms_req_tasklet, (unsigned long)msh);
+	msh->request = j38ms_submit_req;
+	msh->set_param = j38ms_set_param;
 
 	msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8;
 
-	setup_timer(&host->timer, jmb38x_ms_abort, (unsigned long)msh);
+	setup_timer(&host->timer, j38ms_abort, (unsigned long)msh);
 
-	if (!request_irq(host->irq, jmb38x_ms_isr, IRQF_SHARED, host->host_id,
+	if (!request_irq(host->irq, j38ms_isr, IRQF_SHARED, host->host_id,
 			 msh))
 		return msh;
 
@@ -731,19 +731,19 @@ err_out_free:
 	return NULL;
 }
 
-static void jmb38x_ms_free_host(struct memstick_host *msh)
+static void j38ms_free_host(struct memstick_host *msh)
 {
-	struct jmb38x_ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = memstick_priv(msh);
 
 	free_irq(host->irq, msh);
 	iounmap(host->addr);
 	memstick_free_host(msh);
 }
 
-static int jmb38x_ms_probe(struct pci_dev *pdev,
+static int j38ms_probe(struct pci_dev *pdev,
 			   const struct pci_device_id *dev_id)
 {
-	struct jmb38x_ms *jm;
+	struct j38ms *jm;
 	int pci_dev_busy = 0;
 	int rc, cnt;
 
@@ -766,14 +766,14 @@ static int jmb38x_ms_probe(struct pci_dev *pdev,
 	pci_read_config_dword(pdev, 0xac, &rc);
 	pci_write_config_dword(pdev, 0xac, rc | 0x00470000);
 
-	cnt = jmb38x_ms_count_slots(pdev);
+	cnt = j38ms_count_slots(pdev);
 	if (!cnt) {
 		rc = -ENODEV;
 		pci_dev_busy = 1;
 		goto err_out;
 	}
 
-	jm = kzalloc(sizeof(struct jmb38x_ms)
+	jm = kzalloc(sizeof(struct j38ms)
 		     + cnt * sizeof(struct memstick_host *), GFP_KERNEL);
 	if (!jm) {
 		rc = -ENOMEM;
@@ -785,14 +785,14 @@ static int jmb38x_ms_probe(struct pci_dev *pdev,
 	pci_set_drvdata(pdev, jm);
 
 	for (cnt = 0; cnt < jm->host_cnt; ++cnt) {
-		jm->hosts[cnt] = jmb38x_ms_alloc_host(jm, cnt);
+		jm->hosts[cnt] = j38ms_alloc_host(jm, cnt);
 		if (!jm->hosts[cnt])
 			break;
 
 		rc = memstick_add_host(jm->hosts[cnt]);
 
 		if (rc) {
-			jmb38x_ms_free_host(jm->hosts[cnt]);
+			j38ms_free_host(jm->hosts[cnt]);
 			jm->hosts[cnt] = NULL;
 			break;
 		}
@@ -813,10 +813,10 @@ err_out:
 	return rc;
 }
 
-static void jmb38x_ms_remove(struct pci_dev *dev)
+static void j38ms_remove(struct pci_dev *dev)
 {
-	struct jmb38x_ms *jm = pci_get_drvdata(dev);
-	struct jmb38x_ms_host *host;
+	struct j38ms *jm = pci_get_drvdata(dev);
+	struct j38ms_host *host;
 	int cnt;
 	unsigned long flags;
 
@@ -826,7 +826,7 @@ static void jmb38x_ms_remove(struct pci_dev *dev)
 
 		host = memstick_priv(jm->hosts[cnt]);
 
-		jm->hosts[cnt]->request = jmb38x_ms_dummy_submit;
+		jm->hosts[cnt]->request = j38ms_dummy_submit;
 		tasklet_kill(&host->notify);
 		writel(0, host->addr + INT_SIGNAL_ENABLE);
 		writel(0, host->addr + INT_STATUS_ENABLE);
@@ -835,14 +835,14 @@ static void jmb38x_ms_remove(struct pci_dev *dev)
 		spin_lock_irqsave(&host->lock, flags);
 		if (host->req) {
 			host->req->error = -ETIME;
-			jmb38x_ms_complete_cmd(jm->hosts[cnt], 1);
+			j38ms_complete_cmd(jm->hosts[cnt], 1);
 		}
 		spin_unlock_irqrestore(&host->lock, flags);
 
 		memstick_remove_host(jm->hosts[cnt]);
 		dev_dbg(&jm->pdev->dev, "host removed\n");
 
-		jmb38x_ms_free_host(jm->hosts[cnt]);
+		j38ms_free_host(jm->hosts[cnt]);
 	}
 
 	pci_set_drvdata(dev, NULL);
@@ -851,39 +851,39 @@ static void jmb38x_ms_remove(struct pci_dev *dev)
 	kfree(jm);
 }
 
-static struct pci_device_id jmb38x_ms_id_tbl [] = {
+static struct pci_device_id j38ms_id_tbl[] = {
 	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID,
 	  PCI_ANY_ID, 0, 0, 0 },
 	{ }
 };
 
-static struct pci_driver jmb38x_ms_driver = {
+static struct pci_driver j38ms_driver = {
 	.name = DRIVER_NAME,
-	.id_table = jmb38x_ms_id_tbl,
-	.probe = jmb38x_ms_probe,
-	.remove = jmb38x_ms_remove,
-	.suspend = jmb38x_ms_suspend,
-	.resume = jmb38x_ms_resume
+	.id_table = j38ms_id_tbl,
+	.probe = j38ms_probe,
+	.remove = j38ms_remove,
+	.suspend = j38ms_suspend,
+	.resume = j38ms_resume
 };
 
-static int __init jmb38x_ms_init(void)
+static int __init j38ms_init(void)
 {
-	return pci_register_driver(&jmb38x_ms_driver);
+	return pci_register_driver(&j38ms_driver);
 }
 
-static void __exit jmb38x_ms_exit(void)
+static void __exit j38ms_exit(void)
 {
-	pci_unregister_driver(&jmb38x_ms_driver);
+	pci_unregister_driver(&j38ms_driver);
 }
 
 MODULE_AUTHOR("Alex Dubov");
 MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver");
 MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl);
+MODULE_DEVICE_TABLE(pci, j38ms_id_tbl);
 
 module_param(no_dma, bool, S_IRUGO);
 module_param(debug, bool, S_IRUGO);
 
 
-module_init(jmb38x_ms_init);
-module_exit(jmb38x_ms_exit);
+module_init(j38ms_init);
+module_exit(j38ms_exit);
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index 5bca4b3..c64f2e1 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -142,8 +142,8 @@
 #define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00
 #define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000
 
-struct jmb38x_ms_host {
-	struct jmb38x_ms        *chip;
+struct j38ms_host {
+	struct j38ms            *chip;
 	void __iomem            *addr;
 	spinlock_t              lock;
 	struct tasklet_struct   notify;
@@ -159,7 +159,7 @@ struct jmb38x_ms_host {
 	unsigned int            io_word[2];
 };
 
-struct jmb38x_ms {
+struct j38ms {
 	struct pci_dev        *pdev;
 	int                   host_cnt;
 	struct memstick_host  *hosts[];
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together.
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (15 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:00   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 18/29] memstick: jmb38x_ms: rename functions Maxim Levitsky
                   ` (12 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

No functional changes, just group these funtions together.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |  104 ++++++++++++++++++------------------
 drivers/memstick/host/jmb38x_ms.h |    8 +++
 2 files changed, 60 insertions(+), 52 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index e896a4d..2e10104 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -60,32 +60,6 @@ static unsigned int j38ms_read_data(struct j38ms_host *host,
 	return off;
 }
 
-static unsigned int j38ms_read_reg_data(struct j38ms_host *host,
-					    unsigned char *buf,
-					    unsigned int length)
-{
-	unsigned int off = 0;
-
-	while (host->io_pos > 4 && length) {
-		buf[off++] = host->io_word[0] & 0xff;
-		host->io_word[0] >>= 8;
-		length--;
-		host->io_pos--;
-	}
-
-	if (!length)
-		return off;
-
-	while (host->io_pos && length) {
-		buf[off++] = host->io_word[1] & 0xff;
-		host->io_word[1] >>= 8;
-		length--;
-		host->io_pos--;
-	}
-
-	return off;
-}
-
 static unsigned int j38ms_write_data(struct j38ms_host *host,
 					 unsigned char *buf,
 					 unsigned int length)
@@ -139,32 +113,6 @@ static unsigned int j38ms_write_data(struct j38ms_host *host,
 	return off;
 }
 
-static unsigned int j38ms_write_reg_data(struct j38ms_host *host,
-					     unsigned char *buf,
-					     unsigned int length)
-{
-	unsigned int off = 0;
-
-	while (host->io_pos < 4 && length) {
-		host->io_word[0] &= ~(0xff << (host->io_pos * 8));
-		host->io_word[0] |=  buf[off++] << (host->io_pos * 8);
-		host->io_pos++;
-		length--;
-	}
-
-	if (!length)
-		return off;
-
-	while (host->io_pos < 8 && length) {
-		host->io_word[1] &= ~(0xff << (host->io_pos * 8));
-		host->io_word[1] |=  buf[off++] << (host->io_pos * 8);
-		host->io_pos++;
-		length--;
-	}
-
-	return off;
-}
-
 static int j38ms_transfer_data(struct j38ms_host *host)
 {
 	unsigned int length;
@@ -232,6 +180,58 @@ static int j38ms_transfer_data(struct j38ms_host *host)
 	return length;
 }
 
+static unsigned int j38ms_read_reg_data(struct j38ms_host *host,
+					    unsigned char *buf,
+					    unsigned int length)
+{
+	unsigned int off = 0;
+
+	while (host->io_pos > 4 && length) {
+		buf[off++] = host->io_word[0] & 0xff;
+		host->io_word[0] >>= 8;
+		length--;
+		host->io_pos--;
+	}
+
+	if (!length)
+		return off;
+
+	while (host->io_pos && length) {
+		buf[off++] = host->io_word[1] & 0xff;
+		host->io_word[1] >>= 8;
+		length--;
+		host->io_pos--;
+	}
+
+	return off;
+}
+
+static unsigned int j38ms_write_reg_data(struct j38ms_host *host,
+					     unsigned char *buf,
+					     unsigned int length)
+{
+	unsigned int off = 0;
+
+	while (host->io_pos < 4 && length) {
+		host->io_word[0] &= ~(0xff << (host->io_pos * 8));
+		host->io_word[0] |=  buf[off++] << (host->io_pos * 8);
+		host->io_pos++;
+		length--;
+	}
+
+	if (!length)
+		return off;
+
+	while (host->io_pos < 8 && length) {
+		host->io_word[1] &= ~(0xff << (host->io_pos * 8));
+		host->io_word[1] |=  buf[off++] << (host->io_pos * 8);
+		host->io_pos++;
+		length--;
+	}
+
+	return off;
+}
+
 static int j38ms_issue_cmd(struct memstick_host *msh)
 {
 	struct j38ms_host *host = memstick_priv(msh);
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index c64f2e1..a940b5d 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -186,3 +186,11 @@ enum {
 #define dbg(host, format, ...)		__dbg(host, 1, format, ## __VA_ARGS__)
 #define dbg_v(host, format, ...)	__dbg(host, 2, format, ## __VA_ARGS__)
 #define dbg_reg(host, format, ...)	__dbg(host, 3, format, ## __VA_ARGS__)
+
+static unsigned int j38ms_read_reg_data(struct j38ms_host *host,
+					    unsigned char *buf,
+					    unsigned int length);
+
+static unsigned int j38ms_write_reg_data(struct j38ms_host *host,
+					     unsigned char *buf,
+					     unsigned int length);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 18/29] memstick: jmb38x_ms: rename functions
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (16 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:00   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions Maxim Levitsky
                   ` (11 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Give functions names that I hope will describe them better.
Its a matter of personal taste somewhat, I admit.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |   38 ++++++++++++++++++------------------
 drivers/memstick/host/jmb38x_ms.h |    4 +-
 2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 2e10104..295f755 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -22,7 +22,7 @@
 static int no_dma;
 static int debug;
 
-static unsigned int j38ms_read_data(struct j38ms_host *host,
+static unsigned int j38ms_read_fifo_pio(struct j38ms_host *host,
 					unsigned char *buf, unsigned int length)
 {
 	unsigned int off = 0;
@@ -60,7 +60,7 @@ static unsigned int j38ms_read_data(struct j38ms_host *host,
 	return off;
 }
 
-static unsigned int j38ms_write_data(struct j38ms_host *host,
+static unsigned int j38ms_write_fifo_pio(struct j38ms_host *host,
 					 unsigned char *buf,
 					 unsigned int length)
 {
@@ -149,12 +149,12 @@ static int j38ms_transfer_data(struct j38ms_host *host)
 
 		if (host->req->data_dir == WRITE)
 			t_size = !(host->cmd_flags & REG_DATA)
-				 ? j38ms_write_data(host, buf, p_cnt)
-				 : j38ms_write_reg_data(host, buf, p_cnt);
+				 ? j38ms_write_fifo_pio(host, buf, p_cnt)
+				 : j38ms_write_tpc_inline(host, buf, p_cnt);
 		else
 			t_size = !(host->cmd_flags & REG_DATA)
-				 ? j38ms_read_data(host, buf, p_cnt)
-				 : j38ms_read_reg_data(host, buf, p_cnt);
+				 ? j38ms_read_fifo_pio(host, buf, p_cnt)
+				 : j38ms_read_tpc_inline(host, buf, p_cnt);
 
 		if (host->req->long_data) {
 			kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ);
@@ -180,7 +180,7 @@ static int j38ms_transfer_data(struct j38ms_host *host)
 	return length;
 }
 
-static unsigned int j38ms_read_reg_data(struct j38ms_host *host,
+static unsigned int j38ms_read_tpc_inline(struct j38ms_host *host,
 					    unsigned char *buf,
 					    unsigned int length)
 {
@@ -206,7 +206,7 @@ static unsigned int j38ms_read_reg_data(struct j38ms_host *host,
 	return off;
 }
 
-static unsigned int j38ms_write_reg_data(struct j38ms_host *host,
+static unsigned int j38ms_write_tpc_inline(struct j38ms_host *host,
 					     unsigned char *buf,
 					     unsigned int length)
 {
@@ -232,7 +232,7 @@ static unsigned int j38ms_write_reg_data(struct j38ms_host *host,
 	return off;
 }
 
-static int j38ms_issue_cmd(struct memstick_host *msh)
+static int j38ms_execute_tpc(struct memstick_host *msh)
 {
 	struct j38ms_host *host = memstick_priv(msh);
 	unsigned char *data;
@@ -330,7 +330,7 @@ static int j38ms_issue_cmd(struct memstick_host *msh)
 	return 0;
 }
 
-static void j38ms_complete_cmd(struct memstick_host *msh, int last)
+static void j38ms_complete_tpc(struct memstick_host *msh, int last)
 {
 	struct j38ms_host *host = memstick_priv(msh);
 	unsigned int t_val = 0;
@@ -370,7 +370,7 @@ static void j38ms_complete_cmd(struct memstick_host *msh, int last)
 	if (!last) {
 		do {
 			rc = memstick_next_req(msh, &host->req);
-		} while (!rc && j38ms_issue_cmd(msh));
+		} while (!rc && j38ms_execute_tpc(msh));
 	} else {
 		do {
 			rc = memstick_next_req(msh, &host->req);
@@ -446,13 +446,13 @@ static irqreturn_t j38ms_isr(int irq, void *dev_id)
 	    && (((host->cmd_flags & CMD_READY)
 		 && (host->cmd_flags & FIFO_READY))
 		|| host->req->error))
-		j38ms_complete_cmd(msh, 0);
+		j38ms_complete_tpc(msh, 0);
 
 	spin_unlock(&host->lock);
 	return IRQ_HANDLED;
 }
 
-static void j38ms_abort(unsigned long data)
+static void j38ms_irq_timeout(unsigned long data)
 {
 	struct memstick_host *msh = (struct memstick_host *)data;
 	struct j38ms_host *host = memstick_priv(msh);
@@ -462,12 +462,12 @@ static void j38ms_abort(unsigned long data)
 	spin_lock_irqsave(&host->lock, flags);
 	if (host->req) {
 		host->req->error = -ETIME;
-		j38ms_complete_cmd(msh, 0);
+		j38ms_complete_tpc(msh, 0);
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void j38ms_req_tasklet(unsigned long data)
+static void j38ms_submit_tasklet(unsigned long data)
 {
 	struct memstick_host *msh = (struct memstick_host *)data;
 	struct j38ms_host *host = memstick_priv(msh);
@@ -479,7 +479,7 @@ static void j38ms_req_tasklet(unsigned long data)
 		do {
 			rc = memstick_next_req(msh, &host->req);
 			dev_dbg(&host->chip->pdev->dev, "tasklet req %d\n", rc);
-		} while (!rc && j38ms_issue_cmd(msh));
+		} while (!rc && j38ms_execute_tpc(msh));
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -713,13 +713,13 @@ static struct memstick_host *j38ms_alloc_host(struct j38ms *jm, int cnt)
 	host->irq = jm->pdev->irq;
 	host->timeout_jiffies = msecs_to_jiffies(1000);
 
-	tasklet_init(&host->notify, j38ms_req_tasklet, (unsigned long)msh);
+	tasklet_init(&host->notify, j38ms_submit_tasklet, (unsigned long)msh);
 	msh->request = j38ms_submit_req;
 	msh->set_param = j38ms_set_param;
 
 	msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8;
 
-	setup_timer(&host->timer, j38ms_abort, (unsigned long)msh);
+	setup_timer(&host->timer, j38ms_irq_timeout, (unsigned long)msh);
 
 	if (!request_irq(host->irq, j38ms_isr, IRQF_SHARED, host->host_id,
 			 msh))
@@ -835,7 +835,7 @@ static void j38ms_remove(struct pci_dev *dev)
 		spin_lock_irqsave(&host->lock, flags);
 		if (host->req) {
 			host->req->error = -ETIME;
-			j38ms_complete_cmd(jm->hosts[cnt], 1);
+			j38ms_complete_tpc(jm->hosts[cnt], 1);
 		}
 		spin_unlock_irqrestore(&host->lock, flags);
 
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index a940b5d..44e1fc1 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -187,10 +187,10 @@ enum {
 #define dbg_v(host, format, ...)	__dbg(host, 2, format, ## __VA_ARGS__)
 #define dbg_reg(host, format, ...)	__dbg(host, 3, format, ## __VA_ARGS__)
 
-static unsigned int j38ms_read_reg_data(struct j38ms_host *host,
+static unsigned int j38ms_read_tpc_inline(struct j38ms_host *host,
 					    unsigned char *buf,
 					    unsigned int length);
 
-static unsigned int j38ms_write_reg_data(struct j38ms_host *host,
+static unsigned int j38ms_write_tpc_inline(struct j38ms_host *host,
 					     unsigned char *buf,
 					     unsigned int length);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (17 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 18/29] memstick: jmb38x_ms: rename functions Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:03   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 20/29] memstick: jmb38x_ms: rework PIO Maxim Levitsky
                   ` (10 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

All over the code it is a bit easier to see the
register access with this patch. Also set/clear mask
helpers refactor code a bit, but the biggest reason
for this patch is to make it possible to trace register
read/writes with a flip of a module param.

Currently these functions are unused, but will be by later code

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |  102 ++++++++++++++++++++++++++++++++++++-
 drivers/memstick/host/jmb38x_ms.h |    1 +
 2 files changed, 102 insertions(+), 1 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 295f755..bcdb785 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -22,8 +22,86 @@
 static int no_dma;
 static int debug;
 
+/* Read a register*/
+static inline u32 j38ms_read_reg(struct j38ms_host *host, int address)
+{
+	u32 value =  readl(host->addr + address);
+	dbg_reg(host, "reg 0x%02x == 0x%08x", address, value);
+	return value;
+}
+
+/* Write a register */
+static inline void j38ms_write_reg(struct j38ms_host *host,
+						int address, u32 value)
+{
+	dbg_reg(host, "reg 0x%02x <- 0x%08x", address, cpu_to_le32(value));
+	writel(value, host->addr + address);
+}
+
+/* Read a register without endiannes conversion*/
+static inline u32 j38ms_read_reg_raw(struct j38ms_host *host, int address)
+{
+	u32 value =  __raw_readl(host->addr + address);
+	dbg_reg(host, "reg 0x%02x == 0x%08x", address, cpu_to_le32(value));
+	return value;
+}
+
+/* Write a register without endiannes conversion */
+static inline void j38ms_write_reg_raw(struct j38ms_host *host,
+						int address, u32 value)
+{
+	dbg_reg(host, "reg 0x%02x <- 0x%08x", address, value);
+	__raw_writel(value, host->addr + address);
+}
+
+/* Set specific bits in a register*/
+static inline void j38ms_set_reg_mask(struct j38ms_host *host,
+						int address, u32 mask)
+{
+	u32 reg = readl(host->addr + address);
+	dbg_reg(host, "reg 0x%02x |= 0x%08x (old =0x%08x)", address, mask, reg);
+	writel(reg | mask , host->addr + address);
+}
+
+/* Clear specific bits in a register*/
+static inline void j38ms_clear_reg_mask(struct j38ms_host *host,
+						int address, u32 mask)
+{
+	u32 reg = readl(host->addr + address);
+	dbg_reg(host, "reg 0x%02x &= 0x%08x (old = 0x%08x, mask = 0x%08x)",
+						address, ~mask, reg, mask);
+	writel(reg & ~mask, host->addr + address);
+}
+
+/* Reads one DWORD via PIO. returns -EAGAIN if fifo is empty */
+static inline int j38ms_read_fifo_dword_pio(struct j38ms_host *host, u32 *dword)
+{
+	if (unlikely(j38ms_read_reg(host, STATUS) & STATUS_FIFO_EMPTY)) {
+		dbg(host, "PIO: FIFO empty");
+		return -EAGAIN;
+	}
+
+	*dword = j38ms_read_reg_raw(host, DATA);
+	dbg(host, "PIO: read: %08x", *dword);
+	return 0;
+}
+
+/* Writes one DWORD via PIO. returns -EAGAIN if fifo is full */
+static inline int j38ms_write_fifo_dword_pio(struct j38ms_host *host, u32 dword)
+{
+	if (unlikely(j38ms_read_reg(host, STATUS) & STATUS_FIFO_FULL)) {
+		dbg(host, "PIO: FIFO full");
+		return -EAGAIN;
+	}
+
+	dbg(host, "PIO: writing: %08x", dword);
+	j38ms_write_reg_raw(host, DATA, dword);
+	return 0;
+}
+
+/* Read TPC data using PIO */
 static unsigned int j38ms_read_fifo_pio(struct j38ms_host *host,
-					unsigned char *buf, unsigned int length)
+				unsigned char *buf, unsigned int length)
 {
 	unsigned int off = 0;
 
@@ -60,6 +138,7 @@ static unsigned int j38ms_read_fifo_pio(struct j38ms_host *host,
 	return off;
 }
 
+/* Write TPC data through normal PIO fifo */
 static unsigned int j38ms_write_fifo_pio(struct j38ms_host *host,
 					 unsigned char *buf,
 					 unsigned int length)
@@ -113,6 +192,7 @@ static unsigned int j38ms_write_fifo_pio(struct j38ms_host *host,
 	return off;
 }
 
+/* Transfer data between current request and FIFO */
 static int j38ms_transfer_data(struct j38ms_host *host)
 {
 	unsigned int length;
@@ -180,6 +260,7 @@ static int j38ms_transfer_data(struct j38ms_host *host)
 	return length;
 }
 
+/* Read short TPC data (up to 8 bytes) via 2 special registers*/
 static unsigned int j38ms_read_tpc_inline(struct j38ms_host *host,
 					    unsigned char *buf,
 					    unsigned int length)
@@ -206,6 +287,7 @@ static unsigned int j38ms_read_tpc_inline(struct j38ms_host *host,
 	return off;
 }
 
+/* Write short TPC data (up to 8 bytes) through 2 special registers */
 static unsigned int j38ms_write_tpc_inline(struct j38ms_host *host,
 					     unsigned char *buf,
 					     unsigned int length)
@@ -232,6 +314,19 @@ static unsigned int j38ms_write_tpc_inline(struct j38ms_host *host,
 	return off;
 }
 
+/*
+ * Start execution of a TPC:
+ * NOTES:
+ *
+ * PIO writes trigger wierd hardware bug that causes DMA writes
+ *  to fail.
+ *
+ * length alignmemt:
+ *	Short (<=8) TPC don't have any alignment problems.
+ *	DMA read/writes must be 4 aligned
+ *	PIO _reads_ must be aligned. Writes can be not aligned
+ *
+ */
 static int j38ms_execute_tpc(struct memstick_host *msh)
 {
 	struct j38ms_host *host = memstick_priv(msh);
@@ -330,6 +425,7 @@ static int j38ms_execute_tpc(struct memstick_host *msh)
 	return 0;
 }
 
+/* Cleanups execution of current TPC */
 static void j38ms_complete_tpc(struct memstick_host *msh, int last)
 {
 	struct j38ms_host *host = memstick_priv(msh);
@@ -380,6 +476,7 @@ static void j38ms_complete_tpc(struct memstick_host *msh, int last)
 	}
 }
 
+/* Interrupt handler */
 static irqreturn_t j38ms_isr(int irq, void *dev_id)
 {
 	struct memstick_host *msh = dev_id;
@@ -452,6 +549,7 @@ static irqreturn_t j38ms_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/* Timer that is executed in absense of the interrupt */
 static void j38ms_irq_timeout(unsigned long data)
 {
 	struct memstick_host *msh = (struct memstick_host *)data;
@@ -496,6 +594,7 @@ static void j38ms_submit_req(struct memstick_host *msh)
 	tasklet_schedule(&host->notify);
 }
 
+/* hardware reset */
 static int j38ms_reset(struct j38ms_host *host)
 {
 	int cnt;
@@ -700,6 +799,7 @@ static struct memstick_host *j38ms_alloc_host(struct j38ms *jm, int cnt)
 		return NULL;
 
 	host = memstick_priv(msh);
+	host->msh = msh;
 	host->chip = jm;
 	host->addr = ioremap(pci_resource_start(jm->pdev, cnt),
 			     pci_resource_len(jm->pdev, cnt));
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index 44e1fc1..35b8bca 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -144,6 +144,7 @@
 
 struct j38ms_host {
 	struct j38ms            *chip;
+	struct memstick_host    *msh;
 	void __iomem            *addr;
 	spinlock_t              lock;
 	struct tasklet_struct   notify;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 20/29] memstick: jmb38x_ms: rework PIO
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (18 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:05   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution Maxim Levitsky
                   ` (9 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Rewrite PIO code to be just simplier and shorter,
and comment not so obivous parts.

Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |  283 +++++++++++++------------------------
 drivers/memstick/host/jmb38x_ms.h |   17 +--
 2 files changed, 103 insertions(+), 197 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index bcdb785..5af0a52 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -17,6 +17,7 @@
 #include <linux/highmem.h>
 #include <linux/memstick.h>
 #include <linux/slab.h>
+#include <linux/scatterlist.h>
 #include "jmb38x_ms.h"
 
 static int no_dma;
@@ -103,39 +104,34 @@ static inline int j38ms_write_fifo_dword_pio(struct j38ms_host *host, u32 dword)
 static unsigned int j38ms_read_fifo_pio(struct j38ms_host *host,
 				unsigned char *buf, unsigned int length)
 {
-	unsigned int off = 0;
+	unsigned int orig_len = length;
+	unsigned char tmp_buf[4];
 
-	while (host->io_pos && length) {
-		buf[off++] = host->io_word[0] & 0xff;
-		host->io_word[0] >>= 8;
-		length--;
-		host->io_pos--;
+	/* Read bytes from last saved part */
+	if (host->pio_tmp_buf_len) {
+		int count = min(host->pio_tmp_buf_len, length);
+		memcpy(buf, host->pio_tmp_buf, count);
+		buf += count;
+		length -= count;
 	}
 
-	if (!length)
-		return off;
+	/* Read aligned data*/
+	for (; length >= 4 ; buf += 4, length -= 4)
+		if (j38ms_read_fifo_dword_pio(host, (u32 *)buf))
+			return orig_len - length;
 
-	while (!(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) {
-		if (length < 4)
-			break;
-		*(unsigned int *)(buf + off) = __raw_readl(host->addr + DATA);
-		length -= 4;
-		off += 4;
-	}
+	/* Read last 4 bytes, and
+			save unconsumed part of it to the pio_tmp_buf */
+	if (length && !j38ms_read_fifo_dword_pio(host, (u32 *)tmp_buf)) {
 
-	if (length
-	    && !(STATUS_FIFO_EMPTY & readl(host->addr + STATUS))) {
-		host->io_word[0] = readl(host->addr + DATA);
-		for (host->io_pos = 4; host->io_pos; --host->io_pos) {
-			buf[off++] = host->io_word[0] & 0xff;
-			host->io_word[0] >>= 8;
-			length--;
-			if (!length)
-				break;
-		}
+		host->pio_tmp_buf_len = 4 - length;
+		memcpy(buf, tmp_buf, length);
+		memcpy(host->pio_tmp_buf,
+				tmp_buf + length, host->pio_tmp_buf_len);
+		length = 0;
 	}
 
-	return off;
+	return orig_len - length;
 }
 
 /* Write TPC data through normal PIO fifo */
@@ -143,175 +139,106 @@ static unsigned int j38ms_write_fifo_pio(struct j38ms_host *host,
 					 unsigned char *buf,
 					 unsigned int length)
 {
-	unsigned int off = 0;
-
-	if (host->io_pos) {
-		while (host->io_pos < 4 && length) {
-			host->io_word[0] |=  buf[off++] << (host->io_pos * 8);
-			host->io_pos++;
-			length--;
+	unsigned int orig_len = length;
+
+	/* Complete the last saved bytes*/
+	if (host->pio_tmp_buf_len) {
+		int count = min(4 - host->pio_tmp_buf_len, length);
+		memcpy(host->pio_tmp_buf + host->pio_tmp_buf_len, buf, count);
+		buf += count;
+		length -= count;
+
+		if (host->pio_tmp_buf_len == 4) {
+			if (j38ms_write_fifo_dword_pio(
+					host, *(u32 *)host->pio_tmp_buf))
+				return orig_len - length;
+			else
+				host->pio_tmp_buf_len = 0;
 		}
 	}
 
-	if (host->io_pos == 4
-	    && !(STATUS_FIFO_FULL & readl(host->addr + STATUS))) {
-		writel(host->io_word[0], host->addr + DATA);
-		host->io_pos = 0;
-		host->io_word[0] = 0;
-	} else if (host->io_pos) {
-		return off;
-	}
-
-	if (!length)
-		return off;
-
-	while (!(STATUS_FIFO_FULL & readl(host->addr + STATUS))) {
-		if (length < 4)
-			break;
-
-		__raw_writel(*(unsigned int *)(buf + off),
-			     host->addr + DATA);
-		length -= 4;
-		off += 4;
-	}
+	/* Write aligned data to hardware */
+	for (; length >= 4 ; length -= 4, buf += 4)
+		if (j38ms_write_fifo_dword_pio(host, *(u32 *)buf))
+			return orig_len - length;
 
-	switch (length) {
-	case 3:
-		host->io_word[0] |= buf[off + 2] << 16;
-		host->io_pos++;
-	case 2:
-		host->io_word[0] |= buf[off + 1] << 8;
-		host->io_pos++;
-	case 1:
-		host->io_word[0] |= buf[off];
-		host->io_pos++;
+	/* Save last 3-1 bytes to buffer, because we can't send them now*/
+	if (length) {
+		memset(host->pio_tmp_buf, 0, 4);
+		memcpy(host->pio_tmp_buf, buf, length);
+		host->pio_tmp_buf_len = length;
 	}
 
-	off += host->io_pos;
-
-	return off;
+	return orig_len - length;
 }
 
+
 /* Transfer data between current request and FIFO */
-static int j38ms_transfer_data(struct j38ms_host *host)
+static void j38ms_transfer_pio(struct j38ms_host *host)
 {
-	unsigned int length;
-	unsigned int off;
-	unsigned int t_size, p_cnt;
 	unsigned char *buf;
-	struct page *pg;
+	unsigned int len;
 	unsigned long flags = 0;
 
-	if (host->req->long_data) {
-		length = host->req->sg.length - host->block_pos;
-		off = host->req->sg.offset + host->block_pos;
-	} else {
-		length = host->req->data_len - host->block_pos;
-		off = 0;
-	}
+	if (host->req->long_data)
+		local_irq_save(flags);
 
-	while (length) {
-		unsigned int uninitialized_var(p_off);
+	dbg_v(host, "PIO: new transfer");
 
+	while (1) {
 		if (host->req->long_data) {
-			pg = nth_page(sg_page(&host->req->sg),
-				      off >> PAGE_SHIFT);
-			p_off = offset_in_page(off);
-			p_cnt = PAGE_SIZE - p_off;
-			p_cnt = min(p_cnt, length);
-
-			local_irq_save(flags);
-			buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + p_off;
+			if (!sg_miter_next(&host->pio_sg_iter))
+				break;
+
+			buf = host->pio_sg_iter.addr;
+			len = host->pio_sg_iter.length;
 		} else {
-			buf = host->req->data + host->block_pos;
-			p_cnt = host->req->data_len - host->block_pos;
+			buf = host->req->data + host->pio_offset;
+			len = host->req->data_len - host->pio_offset;
+
+			if (!len)
+				break;
 		}
 
-		if (host->req->data_dir == WRITE)
-			t_size = !(host->cmd_flags & REG_DATA)
-				 ? j38ms_write_fifo_pio(host, buf, p_cnt)
-				 : j38ms_write_tpc_inline(host, buf, p_cnt);
-		else
-			t_size = !(host->cmd_flags & REG_DATA)
-				 ? j38ms_read_fifo_pio(host, buf, p_cnt)
-				 : j38ms_read_tpc_inline(host, buf, p_cnt);
+		len = host->req->data_dir == WRITE ?
+			j38ms_write_fifo_pio(host, buf, len) :
+			j38ms_read_fifo_pio(host, buf, len);
 
-		if (host->req->long_data) {
-			kunmap_atomic(buf - p_off, KM_BIO_SRC_IRQ);
-			local_irq_restore(flags);
-		}
+		if (host->req->long_data)
+			host->pio_sg_iter.consumed = len;
+		else
+			host->pio_offset += len;
 
-		if (!t_size)
-			break;
-		host->block_pos += t_size;
-		length -= t_size;
-		off += t_size;
+		dbg(host, "PIO: transfered %d bytes", len);
+		if (!len)
+			goto exit;
 	}
 
-	if (!length && host->req->data_dir == WRITE) {
-		if (host->cmd_flags & REG_DATA) {
-			writel(host->io_word[0], host->addr + TPC_P0);
-			writel(host->io_word[1], host->addr + TPC_P1);
-		} else if (host->io_pos) {
-			writel(host->io_word[0], host->addr + DATA);
-		}
+	/* Write last non-complete dword of the data */
+	if (host->req->data_dir == WRITE && host->pio_tmp_buf_len) {
+		if (!j38ms_write_fifo_dword_pio(host,
+						*(u32 *)host->pio_tmp_buf))
+			host->pio_tmp_buf_len = 0;
+	}
+exit:
+	if (host->req->long_data) {
+		sg_miter_stop(&host->pio_sg_iter);
+		local_irq_restore(flags);
 	}
-
-	return length;
 }
 
 /* Read short TPC data (up to 8 bytes) via 2 special registers*/
-static unsigned int j38ms_read_tpc_inline(struct j38ms_host *host,
-					    unsigned char *buf,
-					    unsigned int length)
+static void j38ms_read_tpc_inline(struct j38ms_host *host)
 {
-	unsigned int off = 0;
-
-	while (host->io_pos > 4 && length) {
-		buf[off++] = host->io_word[0] & 0xff;
-		host->io_word[0] >>= 8;
-		length--;
-		host->io_pos--;
-	}
-
-	if (!length)
-		return off;
-
-	while (host->io_pos && length) {
-		buf[off++] = host->io_word[1] & 0xff;
-		host->io_word[1] >>= 8;
-		length--;
-		host->io_pos--;
-	}
-
-	return off;
+       *(u32 *)(host->req->data + 0) = j38ms_read_reg_raw(host, TPC_P0);
+       *(u32 *)(host->req->data + 4) = j38ms_read_reg_raw(host, TPC_P1);
 }
 
 /* Write short TPC data (up to 8 bytes) through 2 special registers */
-static unsigned int j38ms_write_tpc_inline(struct j38ms_host *host,
-					     unsigned char *buf,
-					     unsigned int length)
+static void j38ms_write_tpc_inline(struct j38ms_host *host)
 {
-	unsigned int off = 0;
-
-	while (host->io_pos < 4 && length) {
-		host->io_word[0] &= ~(0xff << (host->io_pos * 8));
-		host->io_word[0] |=  buf[off++] << (host->io_pos * 8);
-		host->io_pos++;
-		length--;
-	}
-
-	if (!length)
-		return off;
-
-	while (host->io_pos < 8 && length) {
-		host->io_word[1] &= ~(0xff << (host->io_pos * 8));
-		host->io_word[1] |=  buf[off++] << (host->io_pos * 8);
-		host->io_pos++;
-		length--;
-	}
-
-	return off;
+	j38ms_write_reg_raw(host, TPC_P0, *(u32 *)(host->req->data + 0));
+	j38ms_write_reg_raw(host, TPC_P1, *(u32 *)(host->req->data + 4));
 }
 
 /*
@@ -344,10 +271,6 @@ static int j38ms_execute_tpc(struct memstick_host *msh)
 	dev_dbg(&msh->dev, "hstatus %08x\n", readl(host->addr + STATUS));
 
 	host->cmd_flags = 0;
-	host->block_pos = 0;
-	host->io_pos = 0;
-	host->io_word[0] = 0;
-	host->io_word[1] = 0;
 
 	cmd = host->req->tpc << 16;
 	cmd |= TPC_DATA_SEL;
@@ -407,11 +330,8 @@ static int j38ms_execute_tpc(struct memstick_host *msh)
 		host->cmd_flags |= REG_DATA;
 		cmd |= data_len & 0xf;
 
-		if (host->req->data_dir == WRITE) {
-			j38ms_transfer_data(host);
-			writel(host->io_word[0], host->addr + TPC_P0);
-			writel(host->io_word[1], host->addr + TPC_P1);
-		}
+		if (host->req->data_dir == WRITE)
+			j38ms_write_tpc_inline(host);
 	}
 
 	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
@@ -504,10 +424,10 @@ static irqreturn_t j38ms_isr(int irq, void *dev_id)
 			} else {
 				if (irq_status & (INT_STATUS_FIFO_RRDY
 						  | INT_STATUS_FIFO_WRDY))
-					j38ms_transfer_data(host);
+					j38ms_transfer_pio(host);
 
 				if (irq_status & INT_STATUS_EOTRAN) {
-					j38ms_transfer_data(host);
+					j38ms_transfer_pio(host);
 					host->cmd_flags |= FIFO_READY;
 				}
 			}
@@ -515,17 +435,8 @@ static irqreturn_t j38ms_isr(int irq, void *dev_id)
 			if (irq_status & INT_STATUS_EOTPC) {
 				host->cmd_flags |= CMD_READY;
 				if (host->cmd_flags & REG_DATA) {
-					if (host->req->data_dir == READ) {
-						host->io_word[0]
-							= readl(host->addr
-								+ TPC_P0);
-						host->io_word[1]
-							= readl(host->addr
-								+ TPC_P1);
-						host->io_pos = 8;
-
-						j38ms_transfer_data(host);
-					}
+					if (host->req->data_dir == READ)
+						j38ms_read_tpc_inline(host);
 					host->cmd_flags |= FIFO_READY;
 				}
 			}
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index 35b8bca..d7dffb6 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -151,13 +151,16 @@ struct j38ms_host {
 	int                     id;
 	char                    host_id[32];
 	int                     irq;
-	unsigned int            block_pos;
 	unsigned long           timeout_jiffies;
 	struct timer_list       timer;
 	struct memstick_request *req;
 	unsigned char           cmd_flags;
-	unsigned char           io_pos;
-	unsigned int            io_word[2];
+
+	/* PIO state */
+	struct sg_mapping_iter  pio_sg_iter;
+	unsigned char		pio_offset;
+	unsigned char           pio_tmp_buf[4];
+	unsigned int            pio_tmp_buf_len;
 };
 
 struct j38ms {
@@ -187,11 +190,3 @@ enum {
 #define dbg(host, format, ...)		__dbg(host, 1, format, ## __VA_ARGS__)
 #define dbg_v(host, format, ...)	__dbg(host, 2, format, ## __VA_ARGS__)
 #define dbg_reg(host, format, ...)	__dbg(host, 3, format, ## __VA_ARGS__)
-
-static unsigned int j38ms_read_tpc_inline(struct j38ms_host *host,
-					    unsigned char *buf,
-					    unsigned int length);
-
-static unsigned int j38ms_write_tpc_inline(struct j38ms_host *host,
-					     unsigned char *buf,
-					     unsigned int length);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (19 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 20/29] memstick: jmb38x_ms: rework PIO Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:08   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 22/29] memstick: jmb38x_ms: rework ISR Maxim Levitsky
                   ` (8 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Code rewritten to make it simplier.
A lot of debug output is added to help
diagnose bugs.

No major functional changes

Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |  199 +++++++++++++++++++++----------------
 drivers/memstick/host/jmb38x_ms.h |    3 +-
 2 files changed, 114 insertions(+), 88 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 5af0a52..d15118a 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -254,94 +254,121 @@ static void j38ms_write_tpc_inline(struct j38ms_host *host)
  *	PIO _reads_ must be aligned. Writes can be not aligned
  *
  */
-static int j38ms_execute_tpc(struct memstick_host *msh)
+
+static int j38ms_execute_tpc(struct j38ms_host *host)
 {
-	struct j38ms_host *host = memstick_priv(msh);
-	unsigned char *data;
-	unsigned int data_len, cmd, t_val;
+	u32 cmd = 0, t_val;
+	unsigned int data_len = host->req->long_data ?
+		host->req->sg.length : host->req->data_len;
+	bool is_read = host->req->data_dir == READ;
+
+	if (!(j38ms_read_reg(host, STATUS) & STATUS_HAS_MEDIA)) {
+		dbg(host, "IO: card removed, refusing to send TPC");
+		host->req->error = -ENODEV;
+		return host->req->error;
+	}
 
-	if (!(STATUS_HAS_MEDIA & readl(host->addr + STATUS))) {
-		dev_dbg(&msh->dev, "no media status\n");
-		host->req->error = -ETIME;
+	if (data_len > BLOCK_SIZE_MASK) {
+		dbg(host, "IO: too long TPC (len: %d)", data_len);
+		host->req->error = -ENOSYS;
 		return host->req->error;
 	}
 
-	dev_dbg(&msh->dev, "control %08x\n", readl(host->addr + HOST_CONTROL));
-	dev_dbg(&msh->dev, "status %08x\n", readl(host->addr + INT_STATUS));
-	dev_dbg(&msh->dev, "hstatus %08x\n", readl(host->addr + STATUS));
+	dbg(host, "IO: Start execution of %s",
+		memstick_debug_get_tpc_name(host->req->tpc));
+
+
+	dbg_v(host, "host control: %08x", j38ms_read_reg(host, HOST_CONTROL));
+	dbg_v(host, "int status: %08x", j38ms_read_reg(host, INT_STATUS));
+	dbg_v(host, "card status: %08x", j38ms_read_reg(host, STATUS));
 
+	host->req->error = 0;
 	host->cmd_flags = 0;
 
 	cmd = host->req->tpc << 16;
-	cmd |= TPC_DATA_SEL;
-
-	if (host->req->data_dir == READ)
+	if (is_read)
 		cmd |= TPC_DIR;
-	if (host->req->need_card_int)
-		cmd |= TPC_WAIT_INT;
-
-	data = host->req->data;
-
-	if (!no_dma)
-		host->cmd_flags |= DMA_DATA;
 
-	if (host->req->long_data) {
-		data_len = host->req->sg.length;
-	} else {
-		data_len = host->req->data_len;
-		host->cmd_flags &= ~DMA_DATA;
+	if (host->req->need_card_int) {
+		dbg_v(host, "IO: Will wait for card interrupt");
+		cmd |= TPC_WAIT_INT;
+		/* No, the TPC_GET_INT doesn't work.... */
 	}
 
-	if (data_len <= 8) {
-		cmd &= ~(TPC_DATA_SEL | 0xf);
+	/* Special case for short TPCs */
+	if (!host->req->long_data && data_len <= 8) {
+		dbg(host, "IO: Using 8 byte register window");
 		host->cmd_flags |= REG_DATA;
 		cmd |= data_len & 0xf;
-		host->cmd_flags &= ~DMA_DATA;
+
+		if (!is_read)
+			j38ms_write_tpc_inline(host);
+		goto exec;
 	}
 
-	if (host->cmd_flags & DMA_DATA) {
-		if (1 != pci_map_sg(host->chip->pdev, &host->req->sg, 1,
-				    host->req->data_dir == READ
-				    ? PCI_DMA_FROMDEVICE
-				    : PCI_DMA_TODEVICE)) {
+	/* Otherwise use internal fifo*/
+	cmd |= TPC_DATA_SEL;
+
+	if (data_len & 0x03) {
+		dbg(host, "Hardware doesn't support not-aligned len TPCs!");
+		host->req->error = -ENOSYS;
+		return host->req->error;
+	}
+
+	/* DMA */
+	if (!no_dma && host->req->long_data) {
+
+		dbg(host, "IO: Using DMA");
+		host->cmd_flags |= DMA_DATA;
+
+		if (pci_map_sg(host->chip->pdev,
+			&host->req->sg, 1, is_read
+			? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE) != 1) {
+
+			dbg(host, "IO: DMA map failed");
 			host->req->error = -ENOMEM;
 			return host->req->error;
 		}
-		data_len = sg_dma_len(&host->req->sg);
-		writel(sg_dma_address(&host->req->sg),
-		       host->addr + DMA_ADDRESS);
-		writel(((1 << 16) & BLOCK_COUNT_MASK)
-		       | (data_len & BLOCK_SIZE_MASK),
-		       host->addr + BLOCK);
-		writel(DMA_CONTROL_ENABLE, host->addr + DMA_CONTROL);
-	} else if (!(host->cmd_flags & REG_DATA)) {
-		writel(((1 << 16) & BLOCK_COUNT_MASK)
-		       | (data_len & BLOCK_SIZE_MASK),
-		       host->addr + BLOCK);
-			t_val = readl(host->addr + INT_STATUS_ENABLE);
-			t_val |= host->req->data_dir == READ
-				 ? INT_STATUS_FIFO_RRDY
-				 : INT_STATUS_FIFO_WRDY;
-
-			writel(t_val, host->addr + INT_STATUS_ENABLE);
-			writel(t_val, host->addr + INT_SIGNAL_ENABLE);
+
+		/* We really shouldn't pretend we support that case */
+		if (sg_dma_len(&host->req->sg) != data_len) {
+			dbg(host, "IO: DMA len mismatch");
+			host->req->error = -EFAULT;
+			return host->req->error;
+		}
+
+		j38ms_write_reg(host, BLOCK, data_len | BLOCK_COUNT_1BLOCK);
+		j38ms_write_reg(host, DMA_ADDRESS,
+					sg_dma_address(&host->req->sg));
+		j38ms_write_reg(host, DMA_CONTROL, DMA_CONTROL_ENABLE);
+	/* PIO */
 	} else {
-		cmd &= ~(TPC_DATA_SEL | 0xf);
-		host->cmd_flags |= REG_DATA;
-		cmd |= data_len & 0xf;
 
-		if (host->req->data_dir == WRITE)
-			j38ms_write_tpc_inline(host);
-	}
+		dbg(host, "IO: Using PIO");
+		host->cmd_flags |= PIO_DATA;
 
-	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
-	writel(HOST_CONTROL_LED | readl(host->addr + HOST_CONTROL),
-	       host->addr + HOST_CONTROL);
-	host->req->error = 0;
+		host->pio_offset = 0;
+		host->pio_tmp_buf_len = 0;
+		memset(host->pio_tmp_buf, 0, 4);
 
-	writel(cmd, host->addr + TPC);
-	dev_dbg(&msh->dev, "executing TPC %08x, len %x\n", cmd, data_len);
+		if (host->req->long_data)
+			sg_miter_start(&host->pio_sg_iter,
+				&host->req->sg, 1, SG_MITER_ATOMIC |
+				(is_read ? SG_MITER_FROM_SG : SG_MITER_TO_SG));
+
+		/* Enable FIFO empty interrupts */
+		t_val = is_read ? INT_STATUS_FIFO_RRDY : INT_STATUS_FIFO_WRDY;
 
+		j38ms_write_reg(host, BLOCK, data_len | BLOCK_COUNT_1BLOCK);
+		j38ms_set_reg_mask(host, INT_SIGNAL_ENABLE, t_val);
+		j38ms_set_reg_mask(host, INT_STATUS_ENABLE, t_val);
+	}
+exec:
+	mod_timer(&host->timer, jiffies + host->timeout_jiffies);
+
+	/* Let the TPC fly... */
+	j38ms_write_reg(host, TPC, cmd);
+	j38ms_set_reg_mask(host, HOST_CONTROL, HOST_CONTROL_LED);
 	return 0;
 }
 
@@ -349,44 +376,42 @@ static int j38ms_execute_tpc(struct memstick_host *msh)
 static void j38ms_complete_tpc(struct memstick_host *msh, int last)
 {
 	struct j38ms_host *host = memstick_priv(msh);
-	unsigned int t_val = 0;
 	int rc;
-
 	del_timer(&host->timer);
 
-	dev_dbg(&msh->dev, "c control %08x\n",
-		readl(host->addr + HOST_CONTROL));
-	dev_dbg(&msh->dev, "c status %08x\n",
-		readl(host->addr + INT_STATUS));
-	dev_dbg(&msh->dev, "c hstatus %08x\n", readl(host->addr + STATUS));
+	dbg(host, "IO: TPC complete (error : %d)", host->req->error);
 
-	host->req->int_reg = readl(host->addr + STATUS) & 0xff;
+	j38ms_write_reg(host, BLOCK, 0);
+	j38ms_write_reg(host, DMA_CONTROL, 0);
 
-	writel(0, host->addr + BLOCK);
-	writel(0, host->addr + DMA_CONTROL);
+	dbg_v(host, "host control: %08x", j38ms_read_reg(host, HOST_CONTROL));
+	dbg_v(host, "int status: %08x", j38ms_read_reg(host, INT_STATUS));
+	dbg_v(host, "card status: %08x", j38ms_read_reg(host, STATUS));
+
+	if (host->req->need_card_int)
+		host->req->int_reg = j38ms_read_reg(host, STATUS) & 0xFF;
 
 	if (host->cmd_flags & DMA_DATA) {
 		pci_unmap_sg(host->chip->pdev, &host->req->sg, 1,
-			     host->req->data_dir == READ
-			     ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-	} else {
-		t_val = readl(host->addr + INT_STATUS_ENABLE);
-		if (host->req->data_dir == READ)
-			t_val &= ~INT_STATUS_FIFO_RRDY;
-		else
-			t_val &= ~INT_STATUS_FIFO_WRDY;
+			host->req->data_dir == READ
+			? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
 
-		writel(t_val, host->addr + INT_STATUS_ENABLE);
-		writel(t_val, host->addr + INT_SIGNAL_ENABLE);
+	} else if (host->cmd_flags & PIO_DATA) {
+		u32 t_val = INT_STATUS_FIFO_RRDY | INT_STATUS_FIFO_WRDY;
+
+		/* This is not known well */
+		j38ms_clear_reg_mask(host, INT_STATUS_ENABLE, t_val);
+
+		/* This disables the IRQ to host, really */
+		j38ms_clear_reg_mask(host, INT_SIGNAL_ENABLE, t_val);
 	}
 
-	writel((~HOST_CONTROL_LED) & readl(host->addr + HOST_CONTROL),
-	       host->addr + HOST_CONTROL);
+	j38ms_clear_reg_mask(host, HOST_CONTROL, HOST_CONTROL_LED);
 
 	if (!last) {
 		do {
 			rc = memstick_next_req(msh, &host->req);
-		} while (!rc && j38ms_execute_tpc(msh));
+		} while (!rc && j38ms_execute_tpc(host));
 	} else {
 		do {
 			rc = memstick_next_req(msh, &host->req);
@@ -488,7 +513,7 @@ static void j38ms_submit_tasklet(unsigned long data)
 		do {
 			rc = memstick_next_req(msh, &host->req);
 			dev_dbg(&host->chip->pdev->dev, "tasklet req %d\n", rc);
-		} while (!rc && j38ms_execute_tpc(msh));
+		} while (!rc && j38ms_execute_tpc(host));
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
 }
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index d7dffb6..429ed49 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -173,7 +173,8 @@ enum {
 	CMD_READY    = 0x01,
 	FIFO_READY   = 0x02,
 	REG_DATA     = 0x04,
-	DMA_DATA     = 0x08
+	DMA_DATA     = 0x08,
+	PIO_DATA     = 0x10
 };
 
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 22/29] memstick: jmb38x_ms: rework ISR
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (20 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:11   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default Maxim Levitsky
                   ` (7 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

New ISR is simplier.
Also it only services the hardware when we expect to
thus it workarounds the stuck write ready bit hw bug.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |   90 +++++++++++++++++++++---------------
 1 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index d15118a..6b87e23 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -426,60 +426,74 @@ static irqreturn_t j38ms_isr(int irq, void *dev_id)
 {
 	struct memstick_host *msh = dev_id;
 	struct j38ms_host *host = memstick_priv(msh);
-	unsigned int irq_status;
+	u32 irq_status;
 
 	spin_lock(&host->lock);
-	irq_status = readl(host->addr + INT_STATUS);
-	dev_dbg(&host->chip->pdev->dev, "irq_status = %08x\n", irq_status);
+	irq_status = j38ms_read_reg(host, INT_STATUS);
+
 	if (irq_status == 0 || irq_status == (~0)) {
 		spin_unlock(&host->lock);
 		return IRQ_NONE;
 	}
 
-	if (host->req) {
-		if (irq_status & INT_STATUS_ANY_ERR) {
-			if (irq_status & INT_STATUS_CRC_ERR)
-				host->req->error = -EILSEQ;
-			else
-				host->req->error = -ETIME;
-		} else {
-			if (host->cmd_flags & DMA_DATA) {
-				if (irq_status & INT_STATUS_EOTRAN)
-					host->cmd_flags |= FIFO_READY;
-			} else {
-				if (irq_status & (INT_STATUS_FIFO_RRDY
-						  | INT_STATUS_FIFO_WRDY))
-					j38ms_transfer_pio(host);
-
-				if (irq_status & INT_STATUS_EOTRAN) {
-					j38ms_transfer_pio(host);
-					host->cmd_flags |= FIFO_READY;
-				}
-			}
-
-			if (irq_status & INT_STATUS_EOTPC) {
-				host->cmd_flags |= CMD_READY;
-				if (host->cmd_flags & REG_DATA) {
-					if (host->req->data_dir == READ)
-						j38ms_read_tpc_inline(host);
-					host->cmd_flags |= FIFO_READY;
-				}
-			}
+	dbg(host, "IRQ: status: %08x", irq_status);
+
+	if (irq_status & INT_STATUS_ANY_ERR)
+		dbg(host, "IRQ: error");
+
+	if (irq_status & INT_STATUS_FIFO_RRDY)
+		dbg(host, "IRQ: FIFO is now ready for reading");
+
+	if (irq_status & INT_STATUS_FIFO_WRDY)
+		dbg(host, "IRQ: FIFO is now ready for writing");
+
+	if (irq_status & INT_STATUS_EOTRAN)
+		dbg(host, "IRQ: FIFO IO tranfer done");
+
+	if (irq_status & INT_STATUS_EOTPC)
+		dbg(host, "IRQ: TPC complete");
+
+	if (!host->req)
+		goto out;
+
+	/* Errors */
+	if (irq_status & INT_STATUS_ANY_ERR) {
+		host->req->error =
+			(irq_status & INT_STATUS_CRC_ERR) ? -EILSEQ : -EIO;
+		goto out;
+	}
+
+	/* End of TPC interrupt */
+	if (irq_status & INT_STATUS_EOTPC) {
+		host->cmd_flags |= CMD_READY;
+
+		if (host->cmd_flags & REG_DATA) {
+			if (host->req->data_dir == READ)
+				j38ms_read_tpc_inline(host);
+			host->cmd_flags |= FIFO_READY;
 		}
 	}
 
+	/* Fifo handling */
+	if (irq_status & INT_STATUS_EOTRAN)
+		host->cmd_flags |= FIFO_READY;
+	else if (irq_status & (INT_STATUS_FIFO_RRDY | INT_STATUS_FIFO_WRDY))
+		if (host->cmd_flags & PIO_DATA)
+			j38ms_transfer_pio(host);
+
+out:
 	if (irq_status & (INT_STATUS_MEDIA_IN | INT_STATUS_MEDIA_OUT)) {
-		dev_dbg(&host->chip->pdev->dev, "media changed\n");
+		dbg(host, "IRQ: media changed");
 		memstick_detect_change(msh);
 	}
 
-	writel(irq_status, host->addr + INT_STATUS);
+	/* Yes, interrupt status is cleared by setting the bits as usual */
+	j38ms_write_reg(host, INT_STATUS, irq_status);
 
-	if (host->req
-	    && (((host->cmd_flags & CMD_READY)
-		 && (host->cmd_flags & FIFO_READY))
-		|| host->req->error))
+	if (host->req && (((host->cmd_flags & CMD_READY)
+		&& (host->cmd_flags & FIFO_READY)) || host->req->error)) {
 		j38ms_complete_tpc(msh, 0);
+	}
 
 	spin_unlock(&host->lock);
 	return IRQ_HANDLED;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (21 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 22/29] memstick: jmb38x_ms: rework ISR Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:12   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another Maxim Levitsky
                   ` (6 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

This is to workaround a wierd hardware bug:

If PIO write is used, and then after it DMA write is used, DMA
engine stops doing writes.
That condition even persists after device reset.

To be maxumum safe, we do dma to a scratch page
and memcpy from/to it.

Besides this change should just improve performance.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |   65 ++++++++++++++++++++++++++----------
 drivers/memstick/host/jmb38x_ms.h |    5 +++
 2 files changed, 52 insertions(+), 18 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 6b87e23..77e4971 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -261,6 +261,7 @@ static int j38ms_execute_tpc(struct j38ms_host *host)
 	unsigned int data_len = host->req->long_data ?
 		host->req->sg.length : host->req->data_len;
 	bool is_read = host->req->data_dir == READ;
+	dma_addr_t dma_address;
 
 	if (!(j38ms_read_reg(host, STATUS) & STATUS_HAS_MEDIA)) {
 		dbg(host, "IO: card removed, refusing to send TPC");
@@ -316,30 +317,40 @@ static int j38ms_execute_tpc(struct j38ms_host *host)
 	}
 
 	/* DMA */
-	if (!no_dma && host->req->long_data) {
+	if (!no_dma) {
 
 		dbg(host, "IO: Using DMA");
 		host->cmd_flags |= DMA_DATA;
 
-		if (pci_map_sg(host->chip->pdev,
-			&host->req->sg, 1, is_read
-			? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE) != 1) {
+		if (host->req->long_data) {
 
-			dbg(host, "IO: DMA map failed");
-			host->req->error = -ENOMEM;
-			return host->req->error;
-		}
+			if (pci_map_sg(host->chip->pdev,
+				&host->req->sg, 1, is_read
+				? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE) != 1) {
+
+				dbg(host, "IO: DMA map failed");
+				host->req->error = -ENOMEM;
+				return host->req->error;
+			}
+
+			/* We really shouldn't pretend we support that case */
+			if (sg_dma_len(&host->req->sg) != data_len) {
+				dbg(host, "IO: DMA len mismatch");
+				host->req->error = -EFAULT;
+				return host->req->error;
+			}
 
-		/* We really shouldn't pretend we support that case */
-		if (sg_dma_len(&host->req->sg) != data_len) {
-			dbg(host, "IO: DMA len mismatch");
-			host->req->error = -EFAULT;
-			return host->req->error;
+			dma_address = sg_dma_address(&host->req->sg);
+
+		} else {
+			if (!is_read)
+				memcpy(host->dma_bounce_page,
+					host->req->data, data_len);
+			dma_address = host->dma_bus_address;
 		}
 
 		j38ms_write_reg(host, BLOCK, data_len | BLOCK_COUNT_1BLOCK);
-		j38ms_write_reg(host, DMA_ADDRESS,
-					sg_dma_address(&host->req->sg));
+		j38ms_write_reg(host, DMA_ADDRESS, dma_address);
 		j38ms_write_reg(host, DMA_CONTROL, DMA_CONTROL_ENABLE);
 	/* PIO */
 	} else {
@@ -392,9 +403,13 @@ static void j38ms_complete_tpc(struct memstick_host *msh, int last)
 		host->req->int_reg = j38ms_read_reg(host, STATUS) & 0xFF;
 
 	if (host->cmd_flags & DMA_DATA) {
-		pci_unmap_sg(host->chip->pdev, &host->req->sg, 1,
-			host->req->data_dir == READ
-			? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+		if (host->req->long_data)
+			pci_unmap_sg(host->chip->pdev, &host->req->sg, 1,
+				host->req->data_dir == READ
+				? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+		else if (host->req->data_dir == READ)
+			memcpy(host->req->data,
+				host->dma_bounce_page, host->req->data_len);
 
 	} else if (host->cmd_flags & PIO_DATA) {
 		u32 t_val = INT_STATUS_FIFO_RRDY | INT_STATUS_FIFO_WRDY;
@@ -771,12 +786,23 @@ static struct memstick_host *j38ms_alloc_host(struct j38ms *jm, int cnt)
 
 	setup_timer(&host->timer, j38ms_irq_timeout, (unsigned long)msh);
 
+	host->dma_bounce_page = pci_alloc_consistent(
+				jm->pdev, PAGE_SIZE, &host->dma_bus_address);
+
+	if (!host->dma_bounce_page)
+		goto err_out_free;
+
 	if (!request_irq(host->irq, j38ms_isr, IRQF_SHARED, host->host_id,
 			 msh))
 		return msh;
 
 	iounmap(host->addr);
 err_out_free:
+
+	if (host->dma_bounce_page)
+		pci_free_consistent(jm->pdev, PAGE_SIZE,
+			host->dma_bounce_page, host->dma_bus_address);
+
 	kfree(msh);
 	return NULL;
 }
@@ -787,6 +813,9 @@ static void j38ms_free_host(struct memstick_host *msh)
 
 	free_irq(host->irq, msh);
 	iounmap(host->addr);
+
+	pci_free_consistent(host->chip->pdev, PAGE_SIZE,
+		host->dma_bounce_page, host->dma_bus_address);
 	memstick_free_host(msh);
 }
 
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index 429ed49..5599803 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -161,6 +161,11 @@ struct j38ms_host {
 	unsigned char		pio_offset;
 	unsigned char           pio_tmp_buf[4];
 	unsigned int            pio_tmp_buf_len;
+
+	/* DMA bounce buffer */
+	void			*dma_bounce_page;
+	dma_addr_t		dma_bus_address;
+
 };
 
 struct j38ms {
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another.
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (22 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:14   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 25/29] memstick: jmb38x_ms: pass j38ms_host to few functions instead of memstick_host Maxim Levitsky
                   ` (5 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky, Maxim Levitsky

Lift some common code.
Also make sure new TPC is always exacuted from a tasklet.
While this decreases IO speed a bit, this makes sure
we won't have large latency.

Signed-off-by: Maxim Levitsky <maxim-levitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |   74 ++++++++++++++++++-------------------
 drivers/memstick/host/jmb38x_ms.h |    5 ++-
 2 files changed, 40 insertions(+), 39 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 77e4971..16d022e 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -263,6 +263,11 @@ static int j38ms_execute_tpc(struct j38ms_host *host)
 	bool is_read = host->req->data_dir == READ;
 	dma_addr_t dma_address;
 
+	if (host->dead) {
+		host->req->error = -ETIME;
+		return 0;
+	}
+
 	if (!(j38ms_read_reg(host, STATUS) & STATUS_HAS_MEDIA)) {
 		dbg(host, "IO: card removed, refusing to send TPC");
 		host->req->error = -ENODEV;
@@ -384,10 +389,9 @@ exec:
 }
 
 /* Cleanups execution of current TPC */
-static void j38ms_complete_tpc(struct memstick_host *msh, int last)
+static void j38ms_complete_tpc(struct memstick_host *msh)
 {
 	struct j38ms_host *host = memstick_priv(msh);
-	int rc;
 	del_timer(&host->timer);
 
 	dbg(host, "IO: TPC complete (error : %d)", host->req->error);
@@ -422,18 +426,6 @@ static void j38ms_complete_tpc(struct memstick_host *msh, int last)
 	}
 
 	j38ms_clear_reg_mask(host, HOST_CONTROL, HOST_CONTROL_LED);
-
-	if (!last) {
-		do {
-			rc = memstick_next_req(msh, &host->req);
-		} while (!rc && j38ms_execute_tpc(host));
-	} else {
-		do {
-			rc = memstick_next_req(msh, &host->req);
-			if (!rc)
-				host->req->error = -ETIME;
-		} while (!rc);
-	}
 }
 
 /* Interrupt handler */
@@ -507,7 +499,8 @@ out:
 
 	if (host->req && (((host->cmd_flags & CMD_READY)
 		&& (host->cmd_flags & FIFO_READY)) || host->req->error)) {
-		j38ms_complete_tpc(msh, 0);
+		j38ms_complete_tpc(msh);
+		tasklet_schedule(&host->tasklet);
 	}
 
 	spin_unlock(&host->lock);
@@ -525,7 +518,8 @@ static void j38ms_irq_timeout(unsigned long data)
 	spin_lock_irqsave(&host->lock, flags);
 	if (host->req) {
 		host->req->error = -ETIME;
-		j38ms_complete_tpc(msh, 0);
+		j38ms_complete_tpc(msh);
+		tasklet_schedule(&host->tasklet);
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -535,30 +529,29 @@ static void j38ms_submit_tasklet(unsigned long data)
 	struct memstick_host *msh = (struct memstick_host *)data;
 	struct j38ms_host *host = memstick_priv(msh);
 	unsigned long flags;
-	int rc;
 
 	spin_lock_irqsave(&host->lock, flags);
-	if (!host->req) {
-		do {
-			rc = memstick_next_req(msh, &host->req);
-			dev_dbg(&host->chip->pdev->dev, "tasklet req %d\n", rc);
-		} while (!rc && j38ms_execute_tpc(host));
-	}
+	j38ms_next_request(host);
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static void j38ms_dummy_submit(struct memstick_host *msh)
-{
-	return;
-}
-
 static void j38ms_submit_req(struct memstick_host *msh)
 {
 	struct j38ms_host *host = memstick_priv(msh);
 
-	tasklet_schedule(&host->notify);
+	if (!host->req)
+		tasklet_schedule(&host->tasklet);
 }
 
+/* Asks for next request from upper layer and starts its execution */
+static void j38ms_next_request(struct j38ms_host *host)
+{
+	while (!memstick_next_req(host->msh, &host->req))
+		if (!j38ms_execute_tpc(host))
+			return;
+}
+
+
 /* hardware reset */
 static int j38ms_reset(struct j38ms_host *host)
 {
@@ -747,7 +740,6 @@ static int j38ms_count_slots(struct pci_dev *pdev)
 
 		if (256 != pci_resource_len(pdev, cnt))
 			break;
-
 		++rc;
 	}
 	return rc;
@@ -816,6 +808,7 @@ static void j38ms_free_host(struct memstick_host *msh)
 
 	pci_free_consistent(host->chip->pdev, PAGE_SIZE,
 		host->dma_bounce_page, host->dma_bus_address);
+
 	memstick_free_host(msh);
 }
 
@@ -905,21 +898,26 @@ static void j38ms_remove(struct pci_dev *dev)
 
 		host = memstick_priv(jm->hosts[cnt]);
 
-		jm->hosts[cnt]->request = j38ms_dummy_submit;
-		tasklet_kill(&host->notify);
-		writel(0, host->addr + INT_SIGNAL_ENABLE);
-		writel(0, host->addr + INT_STATUS_ENABLE);
-		mmiowb();
-		dev_dbg(&jm->pdev->dev, "interrupts off\n");
+		tasklet_kill(&host->tasklet);
+
 		spin_lock_irqsave(&host->lock, flags);
+		host->dead = true;
+
+		j38ms_write_reg(host, INT_SIGNAL_ENABLE, 0);
+		j38ms_write_reg(host, INT_STATUS_ENABLE, 0);
+
+		mmiowb();
+		dbg(host, "interrupts off");
+
 		if (host->req) {
 			host->req->error = -ETIME;
-			j38ms_complete_tpc(jm->hosts[cnt], 1);
+			j38ms_complete_tpc(jm->hosts[cnt]);
 		}
+
 		spin_unlock_irqrestore(&host->lock, flags);
 
 		memstick_remove_host(jm->hosts[cnt]);
-		dev_dbg(&jm->pdev->dev, "host removed\n");
+		dbg(host, "host removed");
 
 		j38ms_free_host(jm->hosts[cnt]);
 	}
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index 5599803..5d7ad18 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -146,8 +146,9 @@ struct j38ms_host {
 	struct j38ms            *chip;
 	struct memstick_host    *msh;
 	void __iomem            *addr;
+	bool			dead;
 	spinlock_t              lock;
-	struct tasklet_struct   notify;
+	struct tasklet_struct   tasklet;
 	int                     id;
 	char                    host_id[32];
 	int                     irq;
@@ -196,3 +197,5 @@ enum {
 #define dbg(host, format, ...)		__dbg(host, 1, format, ## __VA_ARGS__)
 #define dbg_v(host, format, ...)	__dbg(host, 2, format, ## __VA_ARGS__)
 #define dbg_reg(host, format, ...)	__dbg(host, 3, format, ## __VA_ARGS__)
+
+static void j38ms_next_request(struct j38ms_host *host);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 25/29] memstick: jmb38x_ms: pass j38ms_host to few functions instead of memstick_host
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (23 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-22 23:53 ` [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset Maxim Levitsky
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Just for consistency

Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 16d022e..725b485 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -510,24 +510,24 @@ out:
 /* Timer that is executed in absense of the interrupt */
 static void j38ms_irq_timeout(unsigned long data)
 {
-	struct memstick_host *msh = (struct memstick_host *)data;
-	struct j38ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = (struct j38ms_host *)data;
 	unsigned long flags;
 
-	dev_dbg(&host->chip->pdev->dev, "abort\n");
+	dbg(host, "interrupt timeout");
+
 	spin_lock_irqsave(&host->lock, flags);
 	if (host->req) {
 		host->req->error = -ETIME;
-		j38ms_complete_tpc(msh);
+		j38ms_complete_tpc(host->msh);
 		tasklet_schedule(&host->tasklet);
 	}
+
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static void j38ms_submit_tasklet(unsigned long data)
 {
-	struct memstick_host *msh = (struct memstick_host *)data;
-	struct j38ms_host *host = memstick_priv(msh);
+	struct j38ms_host *host = (struct j38ms_host *)data;
 	unsigned long flags;
 
 	spin_lock_irqsave(&host->lock, flags);
@@ -768,15 +768,15 @@ static struct memstick_host *j38ms_alloc_host(struct j38ms *jm, int cnt)
 	snprintf(host->host_id, sizeof(host->host_id), DRIVER_NAME ":slot%d",
 		 host->id);
 	host->irq = jm->pdev->irq;
-	host->timeout_jiffies = msecs_to_jiffies(1000);
 
-	tasklet_init(&host->notify, j38ms_submit_tasklet, (unsigned long)msh);
 	msh->request = j38ms_submit_req;
 	msh->set_param = j38ms_set_param;
 
 	msh->caps = MEMSTICK_CAP_PAR4 | MEMSTICK_CAP_PAR8;
 
-	setup_timer(&host->timer, j38ms_irq_timeout, (unsigned long)msh);
+	host->timeout_jiffies = msecs_to_jiffies(1000);
+	setup_timer(&host->timer, j38ms_irq_timeout, (unsigned long)host);
+	tasklet_init(&host->tasklet, j38ms_submit_tasklet, (unsigned long)host);
 
 	host->dma_bounce_page = pci_alloc_consistent(
 				jm->pdev, PAGE_SIZE, &host->dma_bus_address);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (24 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 25/29] memstick: jmb38x_ms: pass j38ms_host to few functions instead of memstick_host Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25 16:17   ` Alex Dubov
  2010-10-22 23:53 ` [PATCH 27/29] memstick: jmb38x_ms: minor additions Maxim Levitsky
                   ` (3 subsequent siblings)
  29 siblings, 1 reply; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Move the code into functions.
Reset clock on init - fixes serial mode

Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |  205 +++++++++++++++++++------------------
 drivers/memstick/host/jmb38x_ms.h |   11 +-
 2 files changed, 108 insertions(+), 108 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 725b485..86c003a 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -551,131 +551,132 @@ static void j38ms_next_request(struct j38ms_host *host)
 			return;
 }
 
-
 /* hardware reset */
-static int j38ms_reset(struct j38ms_host *host)
+static int j38ms_reset(struct j38ms_host *host, u32 reset_bit)
 {
-	int cnt;
-
-	writel(HOST_CONTROL_RESET_REQ | HOST_CONTROL_CLOCK_EN
-	       | readl(host->addr + HOST_CONTROL),
-	       host->addr + HOST_CONTROL);
-	mmiowb();
-
-	for (cnt = 0; cnt < 20; ++cnt) {
-		if (!(HOST_CONTROL_RESET_REQ
-		      & readl(host->addr + HOST_CONTROL)))
-			goto reset_next;
+	int i;
+	j38ms_set_reg_mask(host,
+			HOST_CONTROL, reset_bit | HOST_CONTROL_CLOCK_EN);
 
+	for (i = 0; i < 20; ++i) {
+		if (!(j38ms_read_reg(host, HOST_CONTROL) & reset_bit))
+			break;
 		ndelay(20);
 	}
-	dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n");
-	/* return -EIO; */
+	return (j38ms_read_reg(host, HOST_CONTROL) & reset_bit) ? EIO : 0;
+}
+
+/* Enable/disable the device */
+static int j38ms_power_device(struct j38ms_host *host, bool enable)
+{
+	int error;
 
-reset_next:
-	writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN
-	       | readl(host->addr + HOST_CONTROL),
-	       host->addr + HOST_CONTROL);
-	mmiowb();
+	if (enable) {
 
-	for (cnt = 0; cnt < 20; ++cnt) {
-		if (!(HOST_CONTROL_RESET
-		      & readl(host->addr + HOST_CONTROL)))
-			goto reset_ok;
+		error = j38ms_reset(host, HOST_CONTROL_RESET_REQ);
+		error = j38ms_reset(host, HOST_CONTROL_RESET);
+
+		if (error)
+			return error;
+
+		j38ms_write_reg(host, INT_SIGNAL_ENABLE, INT_STATUS_ALL);
+		j38ms_write_reg(host, INT_STATUS_ENABLE, INT_STATUS_ALL);
+		j38ms_write_reg(host, CLOCK_CONTROL, CLOCK_CONTROL_RESET);
+
+		j38ms_write_reg(host, HOST_CONTROL,
+			HOST_CONTROL_POWER_EN |
+			HOST_CONTROL_CLOCK_EN |
+			HOST_CONTROL_HW_OC_P |
+			HOST_CONTROL_TDELAY_EN |
+			HOST_CONTROL_BSY_TIME);
+
+		j38ms_write_reg(host, PAD_PU_PD, host->id ?
+			PAD_PU_PD_ON_MS_SOCK1 : PAD_PU_PD_ON_MS_SOCK0);
+
+		j38ms_write_reg(host, PAD_OUTPUT_ENABLE, PAD_OUTPUT_ENABLE_MS);
+
+	} else {
+		j38ms_clear_reg_mask(host, HOST_CONTROL,
+			HOST_CONTROL_POWER_EN | HOST_CONTROL_CLOCK_EN);
+		j38ms_write_reg(host, PAD_OUTPUT_ENABLE, 0);
+		j38ms_write_reg(host, PAD_PU_PD, PAD_PU_PD_OFF);
+		j38ms_write_reg(host, CLOCK_CONTROL, CLOCK_CONTROL_OFF);
 
-		ndelay(20);
 	}
-	dev_dbg(&host->chip->pdev->dev, "reset timeout\n");
-	return -EIO;
+	msleep(100);
+	return 0;
+}
 
-reset_ok:
-	mmiowb();
-	writel(INT_STATUS_ALL, host->addr + INT_SIGNAL_ENABLE);
-	writel(INT_STATUS_ALL, host->addr + INT_STATUS_ENABLE);
+/* Switch interface */
+static int j38ms_set_interface(struct j38ms_host *host, int interface)
+{
+	u32 host_ctl = j38ms_read_reg(host, HOST_CONTROL);
+	u32 clock_ctl = CLOCK_CONTROL_40MHZ;
+	u32 clock_delay;
+
+	host_ctl &= ~HOST_CONTROL_IF_MASK;
+	pci_read_config_dword(host->chip->pdev, PCI_CTL_CLOCK_DLY_ADDR,
+				&clock_delay);
+
+	clock_delay &= host->id ? ~PCI_CTL_CLOCK_DLY_MASK_B
+				: ~PCI_CTL_CLOCK_DLY_MASK_A;
+
+	if (interface == MEMSTICK_SERIAL) {
+
+		host_ctl |= HOST_CONTROL_IF_SERIAL;
+		clock_ctl = CLOCK_CONTROL_40MHZ;
+
+		host_ctl &= ~HOST_CONTROL_FAST_CLK;
+		host_ctl &= ~HOST_CONTROL_REO;
+		host_ctl |= HOST_CONTROL_REI;
+
+	} else if (interface == MEMSTICK_PAR4) {
+
+		host_ctl |= HOST_CONTROL_IF_PAR4;
+		clock_ctl = CLOCK_CONTROL_40MHZ;
+
+		host_ctl |= HOST_CONTROL_FAST_CLK;
+		host_ctl |= HOST_CONTROL_REO;
+		host_ctl &= ~HOST_CONTROL_REI;
+
+		clock_delay |= host->id ? (4 << 12) : (4 << 8);
+
+	} else if (interface == MEMSTICK_PAR8) {
+
+		host_ctl |= HOST_CONTROL_IF_PAR8;
+		clock_ctl = CLOCK_CONTROL_50MHZ;
+
+		host_ctl |= HOST_CONTROL_FAST_CLK;
+		host_ctl &= ~HOST_CONTROL_REO;
+		host_ctl &= ~HOST_CONTROL_REI;
+	} else
+		return -EINVAL;
+
+	j38ms_write_reg(host, HOST_CONTROL, host_ctl);
+	j38ms_write_reg(host, CLOCK_CONTROL, clock_ctl);
+
+	pci_write_config_dword(host->chip->pdev,
+		PCI_CTL_CLOCK_DLY_ADDR, clock_delay);
+
+	host->interface = interface;
 	return 0;
 }
 
+/* external interface: control hardware settings */
 static int j38ms_set_param(struct memstick_host *msh,
 			       enum memstick_param param,
 			       int value)
 {
 	struct j38ms_host *host = memstick_priv(msh);
-	unsigned int host_ctl = readl(host->addr + HOST_CONTROL);
-	unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0;
-	int rc = 0;
 
 	switch (param) {
 	case MEMSTICK_POWER:
-		if (value == MEMSTICK_POWER_ON) {
-			rc = j38ms_reset(host);
-			if (rc)
-				return rc;
-
-			host_ctl = 7;
-			host_ctl |= HOST_CONTROL_POWER_EN
-				    | HOST_CONTROL_CLOCK_EN
-				    | HOST_CONTROL_HW_OC_P
-				    | HOST_CONTROL_TDELAY_EN;
-			writel(host_ctl, host->addr + HOST_CONTROL);
-
-			writel(host->id ? PAD_PU_PD_ON_MS_SOCK1
-					: PAD_PU_PD_ON_MS_SOCK0,
-			       host->addr + PAD_PU_PD);
-
-			writel(PAD_OUTPUT_ENABLE_MS,
-			       host->addr + PAD_OUTPUT_ENABLE);
-
-			msleep(10);
-			dev_dbg(&host->chip->pdev->dev, "power on\n");
-		} else if (value == MEMSTICK_POWER_OFF) {
-			host_ctl &= ~(HOST_CONTROL_POWER_EN
-				      | HOST_CONTROL_CLOCK_EN);
-			writel(host_ctl, host->addr +  HOST_CONTROL);
-			writel(0, host->addr + PAD_OUTPUT_ENABLE);
-			writel(PAD_PU_PD_OFF, host->addr + PAD_PU_PD);
-			dev_dbg(&host->chip->pdev->dev, "power off\n");
-		} else
-			return -EINVAL;
-		break;
+		return j38ms_power_device(host, (value == MEMSTICK_POWER_ON));
 	case MEMSTICK_INTERFACE:
-		host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT);
-		pci_read_config_dword(host->chip->pdev,
-				      PCI_CTL_CLOCK_DLY_ADDR,
-				      &clock_delay);
-		clock_delay &= host->id ? ~PCI_CTL_CLOCK_DLY_MASK_B
-					: ~PCI_CTL_CLOCK_DLY_MASK_A;
-
-		if (value == MEMSTICK_SERIAL) {
-			host_ctl &= ~HOST_CONTROL_FAST_CLK;
-			host_ctl &= ~HOST_CONTROL_REO;
-			host_ctl |= HOST_CONTROL_IF_SERIAL
-				    << HOST_CONTROL_IF_SHIFT;
-			host_ctl |= HOST_CONTROL_REI;
-			clock_ctl = CLOCK_CONTROL_40MHZ;
-		} else if (value == MEMSTICK_PAR4) {
-			host_ctl |= HOST_CONTROL_FAST_CLK | HOST_CONTROL_REO;
-			host_ctl |= HOST_CONTROL_IF_PAR4
-				    << HOST_CONTROL_IF_SHIFT;
-			host_ctl &= ~HOST_CONTROL_REI;
-			clock_ctl = CLOCK_CONTROL_40MHZ;
-			clock_delay |= host->id ? (4 << 12) : (4 << 8);
-		} else if (value == MEMSTICK_PAR8) {
-			host_ctl |= HOST_CONTROL_FAST_CLK;
-			host_ctl |= HOST_CONTROL_IF_PAR8
-				    << HOST_CONTROL_IF_SHIFT;
-			host_ctl &= ~(HOST_CONTROL_REI | HOST_CONTROL_REO);
-			clock_ctl = CLOCK_CONTROL_50MHZ;
-		} else
-			return -EINVAL;
-
-		writel(host_ctl, host->addr + HOST_CONTROL);
-		writel(clock_ctl, host->addr + CLOCK_CONTROL);
-		pci_write_config_dword(host->chip->pdev,
-				       PCI_CTL_CLOCK_DLY_ADDR,
-				       clock_delay);
-		break;
+		return j38ms_set_interface(host, value);
+	default:
+		return -EINVAL;
 	};
-	return 0;
 }
 
 #ifdef CONFIG_PM
diff --git a/drivers/memstick/host/jmb38x_ms.h b/drivers/memstick/host/jmb38x_ms.h
index 5d7ad18..4ece074 100644
--- a/drivers/memstick/host/jmb38x_ms.h
+++ b/drivers/memstick/host/jmb38x_ms.h
@@ -48,15 +48,13 @@
 #define HOST_CONTROL_FAST_CLK   0x00000200
 #define HOST_CONTROL_RESET      0x00000100
 #define HOST_CONTROL_POWER_EN   0x00000080
+#define HOST_CONTROL_IF_PAR4    0x00000010
+#define HOST_CONTROL_IF_PAR8    0x00000030
+#define HOST_CONTROL_IF_MASK    0x00000030
 #define HOST_CONTROL_CLOCK_EN   0x00000040
 #define HOST_CONTROL_REO        0x00000008
 #define HOST_CONTROL_BSY_TIME	0x00000007
-
-#define HOST_CONTROL_IF_SHIFT  4
-#define HOST_CONTROL_IF_SERIAL 0x0
-#define HOST_CONTROL_IF_PAR4   0x1
-#define HOST_CONTROL_IF_PAR8   0x3
-
+#define HOST_CONTROL_IF_SERIAL  0x00000000
 
 /* IO window for PIO access to internal FIFO*/
 #define	DATA                   0x1c
@@ -156,6 +154,7 @@ struct j38ms_host {
 	struct timer_list       timer;
 	struct memstick_request *req;
 	unsigned char           cmd_flags;
+	int                     interface;
 
 	/* PIO state */
 	struct sg_mapping_iter  pio_sg_iter;
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 27/29] memstick: jmb38x_ms: minor additions.
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (25 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-22 23:53 ` [PATCH 28/29] memstick: add support for legacy memorysticks Maxim Levitsky
                   ` (2 subsequent siblings)
  29 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

* Add my copyright
* Add module param descriprion

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/memstick/host/jmb38x_ms.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index 86c003a..0a1bb25 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -2,6 +2,7 @@
  *  jmb38x_ms.c - JMicron jmb38x MemoryStick card reader
  *
  *  Copyright (C) 2008 Alex Dubov <oakad@yahoo.com>
+ *  Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -955,13 +956,15 @@ static void __exit j38ms_exit(void)
 }
 
 MODULE_AUTHOR("Alex Dubov");
-MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver");
+MODULE_DESCRIPTION("JMicron jm38x_ms MemoryStick driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, j38ms_id_tbl);
 
-module_param(no_dma, bool, S_IRUGO);
-module_param(debug, bool, S_IRUGO);
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0-3)");
 
+module_param(no_dma, bool, 0644);
+MODULE_PARM_DESC(no_dma, "Disable the dma");
 
 module_init(j38ms_init);
 module_exit(j38ms_exit);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 28/29] memstick: add support for legacy memorysticks
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (26 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 27/29] memstick: jmb38x_ms: minor additions Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-22 23:53 ` [PATCH 29/29] memstick: Add driver for Ricoh R5C592 Card reader Maxim Levitsky
  2010-10-25  2:01 ` [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
  29 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Huge thanks for Alex Dubov for code that this is based on and for lot,
really lot of help he gave me in understanding MemorySticks and
implementing this driver.  His help made this driver possible.

As any code that works with user data this driver isn't recommened to use
with valuable data.

It tries its best though to avoid data corruption and possible damage to
the card.

Tested with MS DUO 64 MB card on Ricoh and Jmicron reader.

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
Acked-by: Alex Dubov <oakad@yahoo.com>
---
 MAINTAINERS                      |    5 +
 drivers/memstick/core/Kconfig    |   12 +
 drivers/memstick/core/Makefile   |    2 +-
 drivers/memstick/core/ms_block.c | 2226 ++++++++++++++++++++++++++++++++++++++
 drivers/memstick/core/ms_block.h |  229 ++++
 5 files changed, 2473 insertions(+), 1 deletions(-)
 create mode 100644 drivers/memstick/core/ms_block.c
 create mode 100644 drivers/memstick/core/ms_block.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 7679bf3..71df8db 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5443,6 +5443,11 @@ W:	http://tifmxx.berlios.de/
 S:	Maintained
 F:	drivers/memstick/host/tifm_ms.c
 
+SONY MEMORYSTICK STANDARD SUPPORT
+M:	Maxim Levitsky <maximlevitsky@gmail.com>
+S:	Maintained
+F:	drivers/memstick/core/ms_block.*
+
 SOUND
 M:	Jaroslav Kysela <perex@perex.cz>
 M:	Takashi Iwai <tiwai@suse.de>
diff --git a/drivers/memstick/core/Kconfig b/drivers/memstick/core/Kconfig
index 95f1814..f79f2a8 100644
--- a/drivers/memstick/core/Kconfig
+++ b/drivers/memstick/core/Kconfig
@@ -24,3 +24,15 @@ config MSPRO_BLOCK
 	  support. This provides a block device driver, which you can use
 	  to mount the filesystem. Almost everyone wishing MemoryStick
 	  support should say Y or M here.
+
+config MS_BLOCK
+	tristate "MemoryStick Standard device driver"
+	depends on BLOCK && EXPERIMENTAL
+	help
+	  Say Y here to enable the MemoryStick Standard device driver
+	  support. This provides a block device driver, which you can use
+	  to mount the filesystem.
+	  This driver works with old (bulky) MemoryStick and MemoryStick Duo
+	  but not PRO. Say Y if you have such card.
+	  Driver is new and not yet well tested, thus it can damage your card
+	  (even permanently)
diff --git a/drivers/memstick/core/Makefile b/drivers/memstick/core/Makefile
index 8b2b529..19d960b 100644
--- a/drivers/memstick/core/Makefile
+++ b/drivers/memstick/core/Makefile
@@ -7,5 +7,5 @@ ifeq ($(CONFIG_MEMSTICK_DEBUG),y)
 endif
 
 obj-$(CONFIG_MEMSTICK)		+= memstick.o
-
+obj-$(CONFIG_MS_BLOCK)		+= ms_block.o
 obj-$(CONFIG_MSPRO_BLOCK)	+= mspro_block.o
diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
new file mode 100644
index 0000000..eb80649
--- /dev/null
+++ b/drivers/memstick/core/ms_block.c
@@ -0,0 +1,2226 @@
+/*
+ *  ms_block.c - Sony MemoryStick (legacy) storage support
+ *
+ *  Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
+ *  Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Special thanks to Carlos Corbacho for providing various MemoryStick cards
+ * that made this driver possible.
+ *
+ */
+
+#include <linux/blkdev.h>
+#include <linux/mm.h>
+#include <linux/idr.h>
+#include <linux/hdreg.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/memstick.h>
+#include <linux/bitmap.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include "ms_block.h"
+
+static int major;
+static int debug;
+static int cache_flush_timeout = 1000;
+static bool verify_writes;
+
+
+/*
+ * Advance scatterlist by 'consumed' bytes
+ * Returns new scatterlist, or NULL if can't advance that much
+ */
+static struct scatterlist *sg_advance(struct scatterlist *sg, int consumed)
+{
+	while (consumed >= sg->length) {
+		consumed -= sg->length;
+
+		sg = sg_next(sg);
+		if (!sg)
+			break;
+	}
+
+	WARN_ON(!sg && consumed);
+
+	if (!sg)
+		return NULL;
+
+	sg->offset += consumed;
+	sg->length -= consumed;
+
+	if (sg->offset >= PAGE_SIZE) {
+		struct page *page =
+			nth_page(sg_page(sg), sg->offset / PAGE_SIZE);
+		sg_set_page(sg, page, sg->length, sg->offset % PAGE_SIZE);
+	}
+
+	return sg;
+}
+
+/* Calculate number of sg entries in sg list */
+static int sg_nents(struct scatterlist *sg)
+{
+	int nents = 0;
+	while (sg) {
+		nents++;
+		sg = sg_next(sg);
+	}
+
+	return nents;
+}
+
+/* Calculate total lenght of scatterlist */
+static int sg_total_len(struct scatterlist *sg)
+{
+	int len = 0;
+	while (sg) {
+		len += sg->length;
+		sg = sg_next(sg);
+	}
+	return len;
+}
+
+/* Compare contents of an sg to a buffer */
+static bool sg_compare_to_buffer(struct scatterlist *sg, u8 *buffer, size_t len)
+{
+	unsigned long flags;
+	int retval = 0;
+	struct sg_mapping_iter miter;
+
+	if (sg_total_len(sg) < len)
+		return 1;
+
+	local_irq_save(flags);
+	sg_miter_start(&miter, sg, sg_nents(sg),
+				SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+
+	while (sg_miter_next(&miter) && len > 0) {
+
+		int cmplen = min(miter.length, len);
+		if (memcmp(miter.addr, buffer, cmplen)) {
+			retval = 1;
+			break;
+		}
+
+		buffer += cmplen;
+		len -= cmplen;
+	}
+
+	sg_miter_stop(&miter);
+	local_irq_restore(flags);
+	return retval;
+}
+
+/* Get zone at which block with logical address 'lba' lives
+ * Flash is broken into zones.
+ * Each zone consists of 512 eraseblocks, out of which in first
+ * zone 494 are used and 496 are for all following zones.
+ * Therefore zone #0 hosts blocks 0-493, zone #1 blocks 494-988, etc...
+*/
+static int msb_get_zone_from_lba(int lba)
+{
+	if (lba < 494)
+		return 0;
+	return ((lba - 494) / 496) + 1;
+}
+
+/* Get zone of physical block. Trivial */
+static int msb_get_zone_from_pba(int pba)
+{
+	return pba / MS_BLOCKS_IN_ZONE;
+}
+
+/* Debug test to validate free block counts */
+#ifdef DEBUG
+static int msb_validate_used_block_bitmap(struct msb_data *msb)
+{
+	int total_free_blocks = 0;
+	int i;
+
+	for (i = 0 ; i < msb->zone_count ; i++)
+		total_free_blocks += msb->free_block_count[i];
+
+	if (msb->block_count - bitmap_weight(msb->used_blocks_bitmap,
+					msb->block_count) == total_free_blocks)
+		return 0;
+
+	ms_printk("BUG: free block counts don't match the bitmap");
+	msb->read_only = true;
+	return -EINVAL;
+}
+#endif
+
+/* Mark physical block as used */
+static void msb_mark_block_used(struct msb_data *msb, int pba)
+{
+	int zone = msb_get_zone_from_pba(pba);
+
+	if (test_bit(pba, msb->used_blocks_bitmap)) {
+		ms_printk("BUG: attempt to mark "
+			"already used pba %d as used", pba);
+		msb->read_only = true;
+		return;
+	}
+
+#ifdef DEBUG
+	if (msb_validate_used_block_bitmap(msb))
+		return;
+#endif
+	set_bit(pba, msb->used_blocks_bitmap);
+	msb->free_block_count[zone]--;
+}
+
+/* Mark physical block as free */
+static void msb_mark_block_unused(struct msb_data *msb, int pba)
+{
+	int zone = msb_get_zone_from_pba(pba);
+
+	if (!test_bit(pba, msb->used_blocks_bitmap)) {
+		ms_printk("BUG: attempt to mark "
+				"already unused pba %d as unused" , pba);
+		msb->read_only = true;
+		return;
+	}
+
+#ifdef DEBUG
+	if (msb_validate_used_block_bitmap(msb))
+		return;
+#endif
+	clear_bit(pba, msb->used_blocks_bitmap);
+	msb->free_block_count[zone]++;
+}
+
+/*
+ * Create a sg that spans page from current scatterlist
+ * used by read/write functions
+ */
+static void msb_set_sg(struct msb_data *msb, struct scatterlist *sg)
+{
+	int offset = msb->current_sg->offset + msb->sg_offset;
+	struct page *page = nth_page(sg_page(msb->current_sg),
+						offset >> PAGE_SHIFT);
+	sg_init_table(sg, 1);
+	sg_set_page(sg, page, msb->page_size, offset_in_page(offset));
+}
+
+/* Advances the current sg by one page. Returns error if can't */
+static int msb_advance_sg(struct msb_data *msb)
+{
+	msb->sg_offset += msb->page_size;
+
+	if (msb->sg_offset & (msb->page_size - 1)) {
+		ms_printk("BUG: sg not aligned");
+		return -EINVAL;
+	}
+
+	if (msb->sg_offset > msb->current_sg->length) {
+		dbg("BUG: sg overrun");
+		return -EINVAL;
+	}
+
+	if (msb->sg_offset == msb->current_sg->length) {
+		msb->current_sg = sg_next(msb->current_sg);
+		msb->sg_offset = 0;
+	}
+
+	if (!msb->current_sg)
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * This function is a handler for reads of one page from device.
+ * Writes output to msb->current_sg, takes sector address from msb->reg.param
+ * Can also be used to read extra data only. Set params accordintly.
+ */
+static int h_msb_read_page(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct memstick_request *mrq = &card->current_mrq;
+
+	struct scatterlist sg;
+	u8 command, intreg;
+
+	if (mrq->error) {
+		dbg("read_page, unknown error");
+		return memstick_exit_state_machine(card, mrq->error);
+	}
+again:
+	switch (card->state) {
+	case 0: /* Write the sector address */
+		if (!memstick_write_regs(card,
+			offsetof(struct ms_register, param),
+			sizeof(struct ms_param_register),
+			(unsigned char *)&msb->regs.param))
+			return 0;
+		break;
+
+	case 1: /* Execute the read command*/
+		command = MS_CMD_BLOCK_READ;
+		memstick_init_req(card, MS_TPC_SET_CMD, &command, 1);
+		break;
+
+	case 2: /* send INT request */
+		if (memstick_read_int_reg(card, -1))
+			break;
+		card->state++;
+
+	case 3: /* get result of the INT request*/
+		intreg = mrq->data[0];
+		msb->regs.status.interrupt = intreg;
+
+		if (intreg & MEMSTICK_INT_CMDNAK)
+			return memstick_exit_state_machine(card, -EIO);
+
+		if (!(intreg & MEMSTICK_INT_CED)) {
+			card->state--;
+			goto again;
+		}
+
+		if (intreg & MEMSTICK_INT_ERR)
+			card->state++;
+		else
+			card->state = 6;
+
+		goto again;
+
+	case 4: /* read the status register
+				to understand source of the INT_ERR */
+		if (!memstick_read_regs(card,
+			offsetof(struct ms_register, status),
+			sizeof(struct ms_status_register)))
+			return 0;
+		break;
+
+	case 5: /* get results of status check */
+		msb->regs.status = *(struct ms_status_register *)mrq->data;
+		card->state++;
+
+	case 6: /* Send extra data read request */
+		if (!memstick_read_regs(card,
+			offsetof(struct ms_register, extra_data),
+			sizeof(struct ms_extra_data_register)))
+			return 0;
+		break;
+
+	case 7: /* Save result of extra data request */
+		msb->regs.extra_data =
+			*(struct ms_extra_data_register *) mrq->data;
+		card->state++;
+
+	case 8: /* Send the  MS_TPC_READ_LONG_DATA to read IO buffer */
+
+		/* Skip that state if we only read the oob */
+		if (msb->regs.param.cp == MEMSTICK_CP_EXTRA) {
+			card->state++;
+			goto again;
+		}
+
+		msb_set_sg(msb, &sg);
+		memstick_init_req_sg(card, MS_TPC_READ_LONG_DATA, &sg);
+		break;
+
+	case 9: /* check validity of data buffer & done */
+
+		if (!(msb->regs.status.interrupt & MEMSTICK_INT_ERR))
+			return memstick_exit_state_machine(card, 0);
+
+		if (msb->regs.status.status1 & MEMSTICK_UNCORR_ERROR) {
+			dbg("read_page: uncorrectable error");
+			return memstick_exit_state_machine(card, -EBADMSG);
+		}
+
+		if (msb->regs.status.status1 & MEMSTICK_CORR_ERROR) {
+			dbg("read_page: correctable error");
+			return memstick_exit_state_machine(card, -EUCLEAN);
+		} else {
+			dbg("read_page: INT error, but no status error bits");
+			return memstick_exit_state_machine(card, -EIO);
+		}
+	default:
+		BUG();
+	}
+	card->state++;
+	return 0;
+}
+
+/*
+ * Handler of writes of exactly one block.
+ * Takes address from msb->regs.param.
+ * Writes same extra data to blocks, also taken
+ * from msb->regs.extra
+ * Returns -EBADMSG if write fails due to uncorrectable error, or -EIO if
+ * device refuses to take the command or something else
+ */
+static int h_msb_write_block(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct memstick_request *mrq = &card->current_mrq;
+
+	struct scatterlist sg;
+	u8 intreg, command;
+
+	if (mrq->error)
+		return memstick_exit_state_machine(card, mrq->error);
+
+again:
+	switch (card->state) {
+
+	/* HACK: align write on 4 boundary to workaround Jmicron hw bug
+	 * It doen't make sense to use ALIGN here, because its very hardware
+	   specific anyway
+	*/
+
+	case 0: /* write param register*/
+		if (!memstick_write_regs(card,
+			offsetof(struct ms_register, param),
+			sizeof(struct ms_param_register) +
+			sizeof(struct ms_extra_data_register) + 2,
+			(unsigned char *)&msb->regs.param))
+			return 0;
+		break;
+
+	case 1: /* execute the write command*/
+		command = MS_CMD_BLOCK_WRITE;
+		memstick_init_req(card, MS_TPC_SET_CMD, &command, 1);
+		break;
+
+	case 2: /* send INT request */
+		if (memstick_read_int_reg(card, -1))
+			break;
+		card->state++;
+
+	case 3: /* read INT response */
+		intreg = mrq->data[0];
+		msb->regs.status.interrupt = intreg;
+
+		/* errors mean out of here, and fast... */
+		if (intreg & (MEMSTICK_INT_CMDNAK))
+			return memstick_exit_state_machine(card, -EIO);
+
+		if (intreg & MEMSTICK_INT_ERR)
+			return memstick_exit_state_machine(card, -EBADMSG);
+
+
+		/* for last page we need to poll CED */
+		if (msb->current_page == msb->pages_in_block) {
+			if (intreg & MEMSTICK_INT_CED)
+				return memstick_exit_state_machine(card, 0);
+			card->state--;
+			goto again;
+
+		}
+
+		/* for non-last page we need BREQ before writing next chunk */
+		if (!(intreg & MEMSTICK_INT_BREQ)) {
+			card->state--;
+			goto again;
+		}
+
+		card->state++;
+
+	case 4: /* send the MS_TPC_WRITE_LONG_DATA to perform the write*/
+		msb_set_sg(msb, &sg);
+		memstick_init_req_sg(card, MS_TPC_WRITE_LONG_DATA, &sg);
+		mrq->need_card_int = 1;
+		break;
+
+	case 5: /* Switch to next page + go back to int polling */
+		msb->current_page++;
+
+		if (msb->current_page < msb->pages_in_block) {
+			if (msb_advance_sg(msb)) {
+				ms_printk(
+				"BUG: out of data while writing block!");
+				return memstick_exit_state_machine(
+								card, -EFAULT);
+			}
+		}
+		card->state = 2;
+		goto again;
+	default:
+		BUG();
+	}
+	card->state++;
+	return 0;
+}
+
+/*
+ * This function is used to send simple IO requests to device that consist
+ * of register write + command
+ */
+static int h_msb_send_command(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct memstick_request *mrq = &card->current_mrq;
+
+	u8 intreg;
+	int len;
+
+	if (mrq->error) {
+		dbg("send_command: unknown error");
+		return memstick_exit_state_machine(card, mrq->error);
+	}
+
+again:
+	switch (card->state) {
+	case 0: /* write regs */
+		len = sizeof(struct ms_param_register);
+		if (msb->command_need_oob)
+			/* See h_msb_write_block */
+			len += (sizeof(struct ms_extra_data_register) + 2);
+
+		if (!memstick_write_regs(card,
+			offsetof(struct ms_register, param),
+			len,
+			(unsigned char *)&msb->regs.param))
+			return 0;
+		break;
+
+	case 1: /* execute the command*/
+		memstick_init_req(card, MS_TPC_SET_CMD, &msb->command_value, 1);
+		break;
+
+	case 2: /* send INT request */
+		if (memstick_read_int_reg(card, -1))
+			break;
+		card->state++;
+
+	case 3: /* poll for int bits */
+		intreg = mrq->data[0];
+
+		if (intreg & MEMSTICK_INT_CMDNAK)
+			return memstick_exit_state_machine(card, -EIO);
+		if (intreg & MEMSTICK_INT_ERR)
+			return memstick_exit_state_machine(card, -EBADMSG);
+
+
+		if (!(intreg & MEMSTICK_INT_CED)) {
+			card->state--;
+			goto again;
+		}
+
+		return memstick_exit_state_machine(card, 0);
+	}
+	card->state++;
+	return 0;
+}
+
+/* Small handler for card reset */
+static int h_msb_reset(struct memstick_dev *card)
+{
+	u8 command = MS_CMD_RESET;
+	struct memstick_request *mrq = &card->current_mrq;
+
+	if (mrq->error)
+		return memstick_exit_state_machine(card, mrq->error);
+
+	switch (card->state) {
+	case 0:
+		memstick_init_req(card, MS_TPC_SET_CMD, &command, 1);
+		mrq->need_card_int = 0;
+		break;
+	case 1:
+		return memstick_exit_state_machine(card, 0);
+	}
+	card->state++;
+	return 0;
+}
+
+/* This handler is used to do serial->parallel switch */
+static int h_msb_parallel_switch(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct memstick_request *mrq = &card->current_mrq;
+
+	struct memstick_host *host = card->host;
+
+	if (mrq->error) {
+		dbg("parallel_switch: error");
+		msb->regs.param.system &= ~MEMSTICK_SYS_PAM;
+		return memstick_exit_state_machine(card, mrq->error);
+	}
+
+	switch (card->state) {
+
+	case 0: /* Set the parallel interface on memstick side */
+		msb->regs.param.system |= MEMSTICK_SYS_PAM;
+
+		if (!memstick_write_regs(card,
+			offsetof(struct ms_register, param),
+			1,
+			(unsigned char *)&msb->regs.param))
+			return 0;
+		break;
+
+	case 1: /* Set parallel interface on our side + send a dummy request
+			to see if card responds */
+		host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4);
+		memstick_init_req(card, MS_TPC_GET_INT, NULL, 1);
+		break;
+
+	case 2:
+		return memstick_exit_state_machine(card, 0);
+	}
+	card->state++;
+	return 0;
+}
+
+static int msb_switch_to_parallel(struct msb_data *msb);
+
+/* Reset the card, to guard against hw errors beeing treated as bad blocks */
+static int msb_reset(struct msb_data *msb, bool full)
+{
+	bool was_parallel = msb->regs.param.system & MEMSTICK_SYS_PAM;
+	struct memstick_dev *card = msb->card;
+	int error;
+
+	/* Reset the card */
+	msb->regs.param.system = MEMSTICK_SYS_BAMD;
+
+	if (full) {
+		error = memstick_reset(card->host);
+		if (error) {
+			dbg("Failed to reset the host controller");
+			msb->read_only = true;
+			return -EFAULT;
+		}
+	}
+
+	error = memstick_run_state_machine(card, h_msb_reset, true);
+	if (error) {
+		dbg("Failed to reset the card");
+		msb->read_only = true;
+		return -ENODEV;
+	}
+
+	/* Set parallel mode */
+	if (was_parallel)
+		msb_switch_to_parallel(msb);
+	return 0;
+}
+
+/* Attempts to switch interface to parallel mode */
+static int msb_switch_to_parallel(struct msb_data *msb)
+{
+	int error;
+
+	error = memstick_run_state_machine(msb->card,
+						h_msb_parallel_switch, true);
+	if (error) {
+		ms_printk("Switch to parallel failed");
+		msb->regs.param.system &= ~MEMSTICK_SYS_PAM;
+		msb_reset(msb, true);
+		return -EFAULT;
+	}
+
+	msb->card->caps |= MEMSTICK_CAP_AUTO_GET_INT;
+	return 0;
+}
+
+/* Changes overwrite flag on a page */
+static int msb_set_overwrite_flag(struct msb_data *msb,
+						u16 pba, u8 page, u8 flag)
+{
+	if (msb->read_only)
+		return -EROFS;
+
+	msb->regs.param.block_address = cpu_to_be16(pba);
+	msb->regs.param.page_address = page;
+	msb->regs.param.cp = MEMSTICK_CP_OVERWRITE;
+	msb->regs.extra_data.overwrite_flag = flag;
+	msb->command_value = MS_CMD_BLOCK_WRITE;
+	msb->command_need_oob = true;
+
+	dbg_verbose("changing overwrite flag to %02x for sector %d, page %d",
+							flag, pba, page);
+	return memstick_run_state_machine(msb->card, h_msb_send_command, true);
+}
+
+static int msb_mark_bad(struct msb_data *msb, int pba)
+{
+	ms_printk("marking pba %d as bad", pba);
+	msb_reset(msb, true);
+	return msb_set_overwrite_flag(
+			msb, pba, 0, 0xFF & ~MEMSTICK_OVERWRITE_BKST);
+}
+
+static int msb_mark_page_bad(struct msb_data *msb, int pba, int page)
+{
+	dbg("marking page %d of pba %d as bad", page, pba);
+	msb_reset(msb, true);
+	return msb_set_overwrite_flag(msb,
+		pba, page, ~MEMSTICK_OVERWRITE_PGST0);
+}
+
+/* Erases one physical block */
+static int msb_erase_block(struct msb_data *msb, u16 pba)
+{
+	int error, try;
+	if (msb->read_only)
+		return -EROFS;
+
+	dbg_verbose("erasing pba %d", pba);
+
+	for (try = 1 ; try < 3 ; try++) {
+		msb->regs.param.block_address = cpu_to_be16(pba);
+		msb->regs.param.page_address = 0;
+		msb->regs.param.cp = MEMSTICK_CP_BLOCK;
+		msb->command_value = MS_CMD_BLOCK_ERASE;
+		msb->command_need_oob = false;
+
+
+		error = memstick_run_state_machine(msb->card,
+						h_msb_send_command, true);
+		if (!error || msb_reset(msb, true))
+			break;
+	}
+
+	if (error) {
+		ms_printk("erase failed, marking pba %d as bad", pba);
+		msb_mark_bad(msb, pba);
+	}
+
+	dbg_verbose("erase success, marking pba %d as unused", pba);
+	msb_mark_block_unused(msb, pba);
+	set_bit(pba, msb->erased_blocks_bitmap);
+	return error;
+}
+
+/* Reads one page from device */
+static int msb_read_page(struct msb_data *msb,
+	u16 pba, u8 page, struct ms_extra_data_register *extra,
+						struct scatterlist *sg)
+{
+	int try, error;
+
+	if (sg && sg->length < msb->page_size) {
+		ms_printk(
+			"BUG: attempt to read pba %d page %d with too small sg",
+								pba, page);
+		return -EINVAL;
+	}
+
+	if (pba == MS_BLOCK_INVALID) {
+		u8 *ptr;
+		unsigned long flags;
+
+		dbg_verbose("read unmapped sector. returning 0xFF");
+
+		local_irq_save(flags);
+		ptr = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
+		memset(ptr, 0xFF, msb->page_size);
+		kunmap_atomic(ptr - sg->offset, KM_IRQ0);
+		local_irq_restore(flags);
+
+		if (extra)
+			memset(extra, 0xFF, sizeof(*extra));
+		return 0;
+	}
+
+	if (pba >= msb->block_count) {
+		ms_printk("BUG: attempt to read beyond"
+					" the end of the card at pba %d", pba);
+		return -EINVAL;
+	}
+
+	for (try = 1 ; try < 3 ; try++) {
+		msb->regs.param.block_address = cpu_to_be16(pba);
+		msb->regs.param.page_address = page;
+		msb->regs.param.cp = MEMSTICK_CP_PAGE;
+
+		msb->current_sg = sg;
+		msb->sg_offset = 0;
+		error = memstick_run_state_machine(msb->card,
+						h_msb_read_page, true);
+
+
+		if (error == -EUCLEAN) {
+			ms_printk("correctable error on pba %d, page %d",
+				pba, page);
+			error = 0;
+		}
+
+		if (!error && extra)
+			*extra = msb->regs.extra_data;
+
+		if (!error || msb_reset(msb, true))
+			break;
+
+	}
+
+	/* Mark bad pages */
+	if (error == -EBADMSG) {
+		ms_printk("uncorrectable error on read of pba %d, page %d",
+			pba, page);
+
+		if (msb->regs.extra_data.overwrite_flag &
+					MEMSTICK_OVERWRITE_PGST0)
+			msb_mark_page_bad(msb, pba, page);
+		return -EBADMSG;
+	}
+
+	if (error)
+		ms_printk("read of pba %d, page %d failed with error %d",
+			pba, page, error);
+	return error;
+}
+
+/* Reads oob of page only */
+static int msb_read_oob(struct msb_data *msb, u16 pba, u16 page,
+	struct ms_extra_data_register *extra)
+{
+	int error;
+	BUG_ON(!extra);
+
+	msb->regs.param.block_address = cpu_to_be16(pba);
+	msb->regs.param.page_address = page;
+	msb->regs.param.cp = MEMSTICK_CP_EXTRA;
+
+	if (pba > msb->block_count) {
+		ms_printk("BUG: attempt to read beyond"
+					" the end of card at pba %d", pba);
+		return -EINVAL;
+	}
+
+	error = memstick_run_state_machine(msb->card, h_msb_read_page, true);
+	*extra = msb->regs.extra_data;
+
+	if (error == -EUCLEAN) {
+		ms_printk("correctable error on pba %d, page %d",
+			pba, page);
+		return 0;
+	}
+
+	return error;
+}
+
+
+/* Reads a block and compares it with data contained in scatterlist orig_sg */
+static bool msb_verify_block(struct msb_data *msb, u16 pba,
+					struct scatterlist *orig_sg)
+{
+	struct scatterlist sg;
+	int page = 0, error;
+
+	while (page < msb->pages_in_block) {
+		sg_init_one(&sg, msb->block_buffer +
+					page * msb->page_size, msb->page_size);
+
+		error = msb_read_page(msb, pba, page, NULL, &sg);
+		if (error)
+			return -EIO;
+		page++;
+	}
+
+	if (sg_compare_to_buffer(orig_sg, msb->block_buffer, msb->block_size))
+		return -EIO;
+	return 0;
+}
+
+/* Writes exectly one block + oob */
+static int msb_write_block(struct msb_data *msb,
+			u16 pba, u32 lba, struct scatterlist *sg)
+{
+	int error, current_try = 1;
+	BUG_ON(sg->length < msb->page_size);
+
+	if (msb->read_only)
+		return -EROFS;
+
+	if (sg_total_len(sg) < msb->block_size) {
+		ms_printk("BUG: write: sg underrrun");
+		return -EINVAL;
+	}
+
+	if (pba == MS_BLOCK_INVALID) {
+		ms_printk(
+			"BUG: write: attempt to write MS_BLOCK_INVALID block");
+		return -EINVAL;
+	}
+
+	if (pba >= msb->block_count || lba >= msb->logical_block_count) {
+		ms_printk(
+		"BUG: write: attempt to write beyond the end of device");
+		return -EINVAL;
+	}
+
+	if (msb_get_zone_from_lba(lba) != msb_get_zone_from_pba(pba)) {
+		ms_printk("BUG: write: lba zone mismatch");
+		return -EINVAL;
+	}
+
+	if (pba == msb->boot_block_locations[0] ||
+		pba == msb->boot_block_locations[1]) {
+		ms_printk("BUG: write: attempt to write to boot blocks!");
+		return -EINVAL;
+	}
+
+	while (1) {
+
+		if (msb->read_only)
+			return -EROFS;
+
+		msb->regs.param.cp = MEMSTICK_CP_BLOCK;
+		msb->regs.param.page_address = 0;
+		msb->regs.param.block_address = cpu_to_be16(pba);
+
+		msb->regs.extra_data.management_flag = 0xFF;
+		msb->regs.extra_data.overwrite_flag = 0xF8;
+		msb->regs.extra_data.logical_address = cpu_to_be16(lba);
+
+		msb->current_sg = sg;
+		msb->current_page = 0;
+		msb->sg_offset = 0;
+
+		error = memstick_run_state_machine(msb->card,
+						h_msb_write_block, true);
+
+		/* Sector we just wrote to is assumed erased since its pba
+			was erased. If it wasn't erased, write will succeed
+			and will just clear the bits that were set in the block
+			thus test that what we have written,
+			matches what we expect.
+			We do trust the blocks that we erased */
+		if (!error && (verify_writes ||
+				!test_bit(pba, msb->erased_blocks_bitmap)))
+			error = msb_verify_block(msb, pba, sg);
+
+		if (!error)
+			break;
+
+		if (current_try > 1 || msb_reset(msb, true))
+			break;
+
+		ms_printk("write failed, trying to erase the pba %d", pba);
+		error = msb_erase_block(msb, pba);
+		if (error)
+			break;
+
+		current_try++;
+	}
+	return error;
+}
+
+/* Finds a free block for write replacement */
+static u16 msb_get_free_block(struct msb_data *msb, int zone)
+{
+	u16 pos;
+	int pba = zone * MS_BLOCKS_IN_ZONE;
+	int i;
+
+	get_random_bytes(&pos, sizeof(pos));
+
+	if (!msb->free_block_count[zone]) {
+		ms_printk("NO free blocks in the zone %d, to use for a write, "
+			"(media is WORN out) switching to RO mode", zone);
+		msb->read_only = true;
+		return MS_BLOCK_INVALID;
+	}
+
+	pos %= msb->free_block_count[zone];
+
+	dbg_verbose("have %d choices for a free block, selected randomally: %d",
+		msb->free_block_count[zone], pos);
+
+	pba = find_next_zero_bit(msb->used_blocks_bitmap,
+							msb->block_count, pba);
+	for (i = 0 ; i < pos ; ++i)
+		pba = find_next_zero_bit(msb->used_blocks_bitmap,
+						msb->block_count, pba + 1);
+
+	dbg_verbose("result of the free blocks scan: pba %d", pba);
+
+	if (pba == msb->block_count || (msb_get_zone_from_pba(pba)) != zone) {
+		ms_printk("BUG: cant get a free block");
+		msb->read_only = true;
+		return MS_BLOCK_INVALID;
+	}
+
+	msb_mark_block_used(msb, pba);
+	return pba;
+}
+
+static int msb_update_block(struct msb_data *msb, u16 lba,
+	struct scatterlist *sg)
+{
+	u16 pba, new_pba;
+	int error, try;
+
+	pba = msb->lba_to_pba_table[lba];
+	dbg_verbose("start of a block update at lba  %d, pba %d", lba, pba);
+
+	if (pba != MS_BLOCK_INVALID) {
+		dbg_verbose("setting the update flag on the block");
+		msb_set_overwrite_flag(msb, pba, 0,
+				0xFF & ~MEMSTICK_OVERWRITE_UDST);
+	}
+
+	for (try = 0 ; try < 3 ; try++) {
+		new_pba = msb_get_free_block(msb,
+			msb_get_zone_from_lba(lba));
+
+		if (new_pba == MS_BLOCK_INVALID) {
+			error = -EIO;
+			goto out;
+		}
+
+		dbg_verbose("block update: writing updated block to the pba %d",
+								new_pba);
+		error = msb_write_block(msb, new_pba, lba, sg);
+		if (error == -EBADMSG) {
+			msb_mark_bad(msb, new_pba);
+			continue;
+		}
+
+		if (error)
+			goto out;
+
+		dbg_verbose("block update: erasing the old block");
+		msb_erase_block(msb, pba);
+		msb->lba_to_pba_table[lba] = new_pba;
+		return 0;
+	}
+out:
+	if (error) {
+		ms_printk("block update error after %d tries, "
+						"switching to r/o mode", try);
+		msb->read_only = true;
+	}
+	return error;
+}
+
+/* Converts endiannes in the boot block for easy use */
+static void msb_fix_boot_page_endianness(struct ms_boot_page *p)
+{
+	p->header.block_id = be16_to_cpu(p->header.block_id);
+	p->header.format_reserved = be16_to_cpu(p->header.format_reserved);
+	p->entry.disabled_block.start_addr
+		= be32_to_cpu(p->entry.disabled_block.start_addr);
+	p->entry.disabled_block.data_size
+		= be32_to_cpu(p->entry.disabled_block.data_size);
+	p->entry.cis_idi.start_addr
+		= be32_to_cpu(p->entry.cis_idi.start_addr);
+	p->entry.cis_idi.data_size
+		= be32_to_cpu(p->entry.cis_idi.data_size);
+	p->attr.block_size = be16_to_cpu(p->attr.block_size);
+	p->attr.number_of_blocks = be16_to_cpu(p->attr.number_of_blocks);
+	p->attr.number_of_effective_blocks
+		= be16_to_cpu(p->attr.number_of_effective_blocks);
+	p->attr.page_size = be16_to_cpu(p->attr.page_size);
+	p->attr.memory_manufacturer_code
+		= be16_to_cpu(p->attr.memory_manufacturer_code);
+	p->attr.memory_device_code = be16_to_cpu(p->attr.memory_device_code);
+	p->attr.implemented_capacity
+		= be16_to_cpu(p->attr.implemented_capacity);
+	p->attr.controller_number = be16_to_cpu(p->attr.controller_number);
+	p->attr.controller_function = be16_to_cpu(p->attr.controller_function);
+}
+
+static int msb_read_boot_blocks(struct msb_data *msb)
+{
+	int pba = 0;
+	struct scatterlist sg;
+	struct ms_extra_data_register extra;
+	struct ms_boot_page *page;
+
+	msb->boot_block_locations[0] = MS_BLOCK_INVALID;
+	msb->boot_block_locations[1] = MS_BLOCK_INVALID;
+	msb->boot_block_count = 0;
+
+	dbg_verbose("Start of a scan for the boot blocks");
+
+	if (!msb->boot_page) {
+		page = kmalloc(sizeof(struct ms_boot_page) * 2, GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+
+		msb->boot_page = page;
+	}
+
+	msb->block_count = MS_BLOCK_MAX_BOOT_ADDR;
+
+	for (pba = 0 ; pba < MS_BLOCK_MAX_BOOT_ADDR ; pba++) {
+
+		sg_init_one(&sg, page, sizeof(*page));
+		if (msb_read_page(msb, pba, 0, &extra, &sg)) {
+			dbg("boot scan: can't read pba %d", pba);
+			continue;
+		}
+
+		if (extra.management_flag & MEMSTICK_MANAGEMENT_SYSFLG) {
+			dbg("managment flag doesn't indicate boot block %d",
+									pba);
+			continue;
+		}
+
+		if (be16_to_cpu(page->header.block_id) != MS_BLOCK_BOOT_ID) {
+			dbg("the pba at %d doesn' contain boot block ID", pba);
+			continue;
+		}
+
+		msb_fix_boot_page_endianness(page);
+		msb->boot_block_locations[msb->boot_block_count] = pba;
+
+		page++;
+		msb->boot_block_count++;
+
+		if (msb->boot_block_count == 2)
+			break;
+	}
+
+	if (!msb->boot_block_count) {
+		ms_printk("media doesn't contain master page, aborting");
+		return -EIO;
+	}
+
+	dbg_verbose("End of scan for boot blocks");
+	return 0;
+}
+
+static int msb_read_bad_block_table(struct msb_data *msb, int block_nr)
+{
+	struct ms_boot_page *boot_block;
+	struct scatterlist sg;
+	struct scatterlist *sg_ptr = &sg;
+	u16 *buffer = NULL;
+
+	int i, error = 0;
+	int data_size, data_offset, page, page_offset, size_to_read;
+	u16 pba;
+
+	BUG_ON(block_nr > 1);
+
+	boot_block = &msb->boot_page[block_nr];
+	pba = msb->boot_block_locations[block_nr];
+
+	if (msb->boot_block_locations[block_nr] == MS_BLOCK_INVALID)
+		return -EINVAL;
+
+	data_size = boot_block->entry.disabled_block.data_size;
+	data_offset = sizeof(struct ms_boot_page) +
+			boot_block->entry.disabled_block.start_addr;
+	if (!data_size)
+		return 0;
+
+	page = data_offset / msb->page_size;
+	page_offset = data_offset % msb->page_size;
+	size_to_read =
+		DIV_ROUND_UP(data_size + page_offset, msb->page_size) *
+			msb->page_size;
+
+	dbg("reading bad block of boot block at pba %d, offset %d len %d",
+		pba, data_offset, data_size);
+
+	buffer = kzalloc(size_to_read, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	/* Read the buffer */
+	sg_init_one(&sg, buffer, size_to_read);
+
+	while (sg_ptr) {
+		error = msb_read_page(msb, pba, page, NULL, sg_ptr);
+		if (error)
+			goto out;
+
+		sg_ptr = sg_advance(sg_ptr, msb->page_size);
+		page++;
+		if (page == msb->pages_in_block) {
+			ms_printk(
+			"bad block table extends beyond the boot block");
+			break;
+		}
+	}
+
+	/* Process the bad block table */
+	for (i = page_offset ; i < data_size / sizeof(u16) ; i++) {
+
+		u16 bad_block = be16_to_cpu(buffer[i]);
+
+		if (bad_block >= msb->block_count) {
+			dbg("bad block table contains invalid block %d",
+								bad_block);
+			continue;
+		}
+
+		if (test_bit(bad_block, msb->used_blocks_bitmap))  {
+			dbg("duplicate bad block %d in the table",
+				bad_block);
+			continue;
+		}
+
+		dbg("block %d is marked as factory bad", bad_block);
+		msb_mark_block_used(msb, bad_block);
+	}
+out:
+	kfree(buffer);
+	return error;
+}
+
+static int msb_ftl_initialize(struct msb_data *msb)
+{
+	int i;
+
+	if (msb->ftl_initialized)
+		return 0;
+
+	msb->zone_count = msb->block_count / MS_BLOCKS_IN_ZONE;
+	msb->logical_block_count = msb->zone_count * 496 - 2;
+
+	msb->used_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
+	msb->erased_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
+	msb->lba_to_pba_table =
+		kmalloc(msb->logical_block_count * sizeof(u16), GFP_KERNEL);
+
+	if (!msb->used_blocks_bitmap || !msb->lba_to_pba_table ||
+						!msb->erased_blocks_bitmap) {
+		kfree(msb->used_blocks_bitmap);
+		kfree(msb->lba_to_pba_table);
+		kfree(msb->erased_blocks_bitmap);
+		return -ENOMEM;
+	}
+
+	for (i = 0 ; i < msb->zone_count ; i++)
+		msb->free_block_count[i] = MS_BLOCKS_IN_ZONE;
+
+	memset(msb->lba_to_pba_table, MS_BLOCK_INVALID,
+			msb->logical_block_count * sizeof(u16));
+
+	dbg("initial FTL tables created. Zone count = %d, "
+					"Logical block count = %d",
+		msb->zone_count, msb->logical_block_count);
+
+	msb->ftl_initialized = true;
+	return 0;
+}
+
+static int msb_ftl_scan(struct msb_data *msb)
+{
+	u16 pba, lba, other_block;
+	u8 overwrite_flag, managment_flag, other_overwrite_flag;
+	int error;
+	struct ms_extra_data_register extra;
+	u8 *overwrite_flags = kzalloc(msb->block_count, GFP_KERNEL);
+
+	if (!overwrite_flags)
+		return -ENOMEM;
+
+	dbg("Start of media scanning");
+	for (pba = 0 ; pba < msb->block_count ; pba++) {
+
+		if (pba == msb->boot_block_locations[0] ||
+			pba == msb->boot_block_locations[1]) {
+			dbg_verbose("pba %05d -> [boot block]", pba);
+			msb_mark_block_used(msb, pba);
+			continue;
+		}
+
+		if (test_bit(pba, msb->used_blocks_bitmap)) {
+			dbg_verbose("pba %05d -> [factory bad]", pba);
+			continue;
+		}
+
+		error = msb_read_oob(msb, pba, 0, &extra);
+
+		/* can't trust the page if we can't read the oob */
+		if (error == -EBADMSG) {
+			ms_printk(
+			"oob of pba %d damaged, will try to erase it", pba);
+			msb_mark_block_used(msb, pba);
+			msb_erase_block(msb, pba);
+			continue;
+		} else if (error)
+			return error;
+
+		lba = be16_to_cpu(extra.logical_address);
+		managment_flag = extra.management_flag;
+		overwrite_flag = extra.overwrite_flag;
+		overwrite_flags[pba] = overwrite_flag;
+
+		/* Skip bad blocks */
+		if (!(overwrite_flag & MEMSTICK_OVERWRITE_BKST)) {
+			dbg("pba %05d -> [BAD]", pba);
+			msb_mark_block_used(msb, pba);
+			continue;
+		}
+
+		/* Skip system/drm blocks */
+		if ((managment_flag & MEMSTICK_MANAGMENT_FLAG_NORMAL) !=
+			MEMSTICK_MANAGMENT_FLAG_NORMAL) {
+			dbg("pba %05d -> [reserved managment flag %02x]",
+							pba, managment_flag);
+			msb_mark_block_used(msb, pba);
+			continue;
+		}
+
+		/* Erase temporary tables */
+		if (!(managment_flag & MEMSTICK_MANAGEMENT_ATFLG)) {
+			dbg("pba %05d -> [temp table] - will erase", pba);
+
+			msb_mark_block_used(msb, pba);
+			msb_erase_block(msb, pba);
+			continue;
+		}
+
+		if (lba == MS_BLOCK_INVALID) {
+			dbg_verbose("pba %05d -> [free]", pba);
+			continue;
+		}
+
+		msb_mark_block_used(msb, pba);
+
+		/* Block has LBA not according to zoning*/
+		if (msb_get_zone_from_lba(lba) != msb_get_zone_from_pba(pba)) {
+			ms_printk("pba %05d -> [bad lba %05d] - will erase",
+								pba, lba);
+			msb_erase_block(msb, pba);
+			continue;
+		}
+
+		/* No collisions - great */
+		if (msb->lba_to_pba_table[lba] == MS_BLOCK_INVALID) {
+			dbg_verbose("pba %05d -> [lba %05d]", pba, lba);
+			msb->lba_to_pba_table[lba] = pba;
+			continue;
+		}
+
+		other_block = msb->lba_to_pba_table[lba];
+		other_overwrite_flag = overwrite_flags[other_block];
+
+		ms_printk("Collision between pba %d and pba %d",
+			pba, other_block);
+
+		if (!(overwrite_flag & MEMSTICK_OVERWRITE_UDST)) {
+			ms_printk("pba %d is marked as stable, use it", pba);
+			msb_erase_block(msb, other_block);
+			msb->lba_to_pba_table[lba] = pba;
+			continue;
+		}
+
+		if (!(other_overwrite_flag & MEMSTICK_OVERWRITE_UDST)) {
+			ms_printk("pba %d is marked as stable, use it",
+								other_block);
+			msb_erase_block(msb, pba);
+			continue;
+		}
+
+		ms_printk("collision between blocks %d and %d with"
+		" without stable flag set on both, erasing pba %d",
+				pba, other_block, other_block);
+
+		msb_erase_block(msb, other_block);
+		msb->lba_to_pba_table[lba] = pba;
+	}
+
+	dbg("End of media scanning");
+	kfree(overwrite_flags);
+	return 0;
+}
+
+static void msb_cache_flush_timer(unsigned long data)
+{
+	struct msb_data *msb = (struct msb_data *)data;
+	msb->need_flush_cache = true;
+	wake_up_process(msb->io_thread);
+}
+
+
+static void msb_cache_discard(struct msb_data *msb)
+{
+	if (msb->cache_block_lba == MS_BLOCK_INVALID)
+		return;
+
+	del_timer_sync(&msb->cache_flush_timer);
+
+	dbg_verbose("Discarding the write cache");
+	msb->cache_block_lba = MS_BLOCK_INVALID;
+	bitmap_zero(&msb->valid_cache_bitmap, msb->pages_in_block);
+}
+
+static int msb_cache_init(struct msb_data *msb)
+{
+	setup_timer(&msb->cache_flush_timer, msb_cache_flush_timer,
+		(unsigned long)msb);
+
+	if (!msb->cache)
+		msb->cache = kzalloc(msb->block_size, GFP_KERNEL);
+	if (!msb->cache)
+		return -ENOMEM;
+
+	msb_cache_discard(msb);
+	return 0;
+}
+
+static int msb_cache_flush(struct msb_data *msb)
+{
+	struct scatterlist sg;
+	struct ms_extra_data_register extra;
+	int page, offset, error;
+	u16 pba, lba;
+
+	if (msb->read_only)
+		return -EROFS;
+
+	if (msb->cache_block_lba == MS_BLOCK_INVALID)
+		return 0;
+
+	lba = msb->cache_block_lba;
+	pba = msb->lba_to_pba_table[lba];
+
+	dbg_verbose("Flushing the write cache of pba %d (LBA %d)",
+						pba, msb->cache_block_lba);
+
+	/* Read all missing pages in cache */
+	for (page = 0 ; page < msb->pages_in_block ; page++) {
+
+		if (test_bit(page, &msb->valid_cache_bitmap))
+			continue;
+
+		offset = page * msb->page_size;
+		sg_init_one(&sg, msb->cache + offset , msb->page_size);
+
+
+		dbg_verbose("reading non-present sector %d of cache block %d",
+			page, lba);
+		error = msb_read_page(msb, pba, page, &extra, &sg);
+
+		/* Bad pages are copied with 00 page status */
+		if (error == -EBADMSG) {
+			ms_printk("read error on sector %d, contents probably"
+				" damaged", page);
+			continue;
+		}
+
+		if (error)
+			return error;
+
+		if ((extra.overwrite_flag & MEMSTICK_OV_PG_NORMAL) !=
+							MEMSTICK_OV_PG_NORMAL) {
+			dbg("page %d is marked as bad", page);
+			continue;
+		}
+
+		set_bit(page, &msb->valid_cache_bitmap);
+	}
+
+	/* Write the cache now */
+	sg_init_one(&sg, msb->cache , msb->block_size);
+	error = msb_update_block(msb, msb->cache_block_lba, &sg);
+	pba = msb->lba_to_pba_table[msb->cache_block_lba];
+
+	/* Mark invalid pages */
+	if (!error) {
+		for (page = 0 ; page < msb->pages_in_block ; page++) {
+
+			if (test_bit(page, &msb->valid_cache_bitmap))
+				continue;
+
+			dbg("marking page %d as containing damaged data",
+				page);
+			msb_set_overwrite_flag(msb,
+				pba , page, 0xFF & ~MEMSTICK_OV_PG_NORMAL);
+		}
+	}
+
+	msb_cache_discard(msb);
+	return error;
+}
+
+static int msb_cache_write(struct msb_data *msb, int lba,
+		int page, bool add_to_cache_only, struct scatterlist *sg)
+{
+	int error;
+	if (msb->read_only)
+		return -EROFS;
+
+	if (msb->cache_block_lba == MS_BLOCK_INVALID ||
+						lba != msb->cache_block_lba)
+		if (add_to_cache_only)
+			return 0;
+
+	/* If we need to write different block */
+	if (msb->cache_block_lba != MS_BLOCK_INVALID &&
+						lba != msb->cache_block_lba) {
+		dbg_verbose("first flush the cache");
+		error = msb_cache_flush(msb);
+		if (error)
+			return error;
+	}
+
+	if (msb->cache_block_lba  == MS_BLOCK_INVALID) {
+		msb->cache_block_lba  = lba;
+		mod_timer(&msb->cache_flush_timer,
+			jiffies + msecs_to_jiffies(cache_flush_timeout));
+	}
+
+	dbg_verbose("Write of LBA %d page %d to cache ", lba, page);
+
+	sg_copy_to_buffer(sg, 1, msb->cache + page * msb->page_size,
+			msb->page_size);
+	set_bit(page, &msb->valid_cache_bitmap);
+	return 0;
+}
+
+static int msb_cache_read(struct msb_data *msb, int lba,
+					int page, struct scatterlist *sg)
+{
+	int pba = msb->lba_to_pba_table[lba];
+	int error = 0;
+
+	if (lba == msb->cache_block_lba &&
+			test_bit(page, &msb->valid_cache_bitmap)) {
+
+		dbg_verbose("Read of LBA %d (pba %d) sector %d from cache",
+							lba, pba, page);
+		sg_copy_from_buffer(sg, 1,
+			msb->cache + msb->page_size * page,
+							msb->page_size);
+	} else {
+		dbg_verbose("Read of LBA %d (pba %d) sector %d from device",
+							lba, pba, page);
+
+		error = msb_read_page(msb, pba, page, NULL, sg);
+		if (error)
+			return error;
+
+		msb_cache_write(msb, lba, page, true, sg);
+	}
+	return error;
+}
+
+/* Emulated geometry table
+ * This table content isn't that importaint,
+ * One could put here different values, providing that they still
+ * cover whole disk.
+ * 64 MB entry is what windows reports for my 64M memstick */
+
+static const struct chs_entry chs_table[] = {
+/*        size sectors cylynders  heads */
+	{ 4,    16,    247,       2  },
+	{ 8,    16,    495,       2  },
+	{ 16,   16,    495,       4  },
+	{ 32,   16,    991,       4  },
+	{ 64,   16,    991,       8  },
+	{128,   16,    991,       16 },
+	{ 0 }
+};
+
+/* Load information about the card */
+static int msb_init_card(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct memstick_host *host = card->host;
+	struct ms_boot_page *boot_block;
+	int error = 0, i, raw_size_in_megs;
+
+	card->caps = 0;
+
+	if (card->id.class >= MEMSTICK_CLASS_ROM &&
+				card->id.class <= MEMSTICK_CLASS_ROM)
+		msb->read_only = true;
+
+	error = msb_reset(msb, false);
+	if (error)
+		return error;
+
+	msb->page_size = sizeof(struct ms_boot_page);
+
+	/* Read the boot page */
+	error = msb_read_boot_blocks(msb);
+	if (error)
+		return -EIO;
+
+	boot_block = &msb->boot_page[0];
+
+	/* Save intersting attributes from boot page */
+	msb->block_count = boot_block->attr.number_of_blocks;
+	msb->page_size = boot_block->attr.page_size;
+
+	msb->pages_in_block = boot_block->attr.block_size * 2;
+	msb->block_size = msb->page_size * msb->pages_in_block;
+
+	if (msb->page_size > PAGE_SIZE) {
+		/* this isn't supported by linux at all, anyway*/
+		dbg("device page %d size isn't supported", msb->page_size);
+		return -EINVAL;
+	}
+
+	msb->block_buffer = kzalloc(msb->block_size, GFP_KERNEL);
+	if (!msb->block_buffer)
+		return -ENOMEM;
+
+	raw_size_in_megs = (msb->block_size * msb->block_count) >> 20;
+
+	for (i = 0 ; chs_table[i].size ; i++) {
+
+		if (chs_table[i].size != raw_size_in_megs)
+			continue;
+
+		msb->geometry.cylinders = chs_table[i].cyl;
+		msb->geometry.heads = chs_table[i].head;
+		msb->geometry.sectors = chs_table[i].sec;
+		break;
+	}
+
+	if (boot_block->attr.transfer_supporting == 1)
+		card->caps |= MEMSTICK_CAP_PAR4;
+
+	if (boot_block->attr.device_type & 0x03)
+		msb->read_only = true;
+
+	dbg("Total block count = %d", msb->block_count);
+	dbg("Each block consists of %d pages", msb->pages_in_block);
+	dbg("Page size = %d bytes", msb->page_size);
+	dbg("Parallel mode supported: %d", !!(card->caps & MEMSTICK_CAP_PAR4));
+	dbg("Read only: %d", msb->read_only);
+
+	/* Now we can switch the interface */
+	if (host->caps & card->caps & MEMSTICK_CAP_PAR4)
+		msb_switch_to_parallel(msb);
+
+
+	error = msb_cache_init(msb);
+	if (error)
+		return error;
+
+	error = msb_ftl_initialize(msb);
+	if (error)
+		return error;
+
+
+	/* Read the bad block table */
+	error = msb_read_bad_block_table(msb, 0);
+
+	if (error && error != -ENOMEM) {
+		dbg("failed to read bad block table from primary boot block,"
+							" trying from backup");
+		error = msb_read_bad_block_table(msb, 1);
+	}
+
+	if (error)
+		return error;
+
+	/* *drum roll* Scan the media */
+	error = msb_ftl_scan(msb);
+	if (error) {
+		ms_printk("Scan of media failed");
+		return error;
+	}
+
+	return 0;
+
+}
+
+static int msb_do_write_request(struct msb_data *msb, int lba,
+		int page, struct scatterlist *sg, int *sucessfuly_written)
+{
+	int error = 0;
+	*sucessfuly_written = 0;
+
+	while (sg) {
+		if (page == 0 && sg_total_len(sg) >= msb->block_size) {
+
+			if (msb->cache_block_lba == lba)
+				msb_cache_discard(msb);
+
+			dbg_verbose("Writing whole lba %d", lba);
+			error = msb_update_block(msb, lba, sg);
+			if (error)
+				return error;
+
+			sg = sg_advance(sg, msb->block_size);
+			*sucessfuly_written += msb->block_size;
+			lba++;
+			continue;
+		}
+
+		error = msb_cache_write(msb, lba, page, false, sg);
+		if (error)
+			return error;
+
+		sg = sg_advance(sg, msb->page_size);
+		*sucessfuly_written += msb->page_size;
+
+		page++;
+		if (page == msb->pages_in_block) {
+			page = 0;
+			lba++;
+		}
+	}
+	return 0;
+}
+
+static int msb_do_read_request(struct msb_data *msb, int lba,
+		int page, struct scatterlist *sg, int *sucessfuly_read)
+{
+	int error = 0;
+	*sucessfuly_read = 0;
+
+	while (sg) {
+
+		error = msb_cache_read(msb, lba, page, sg);
+		if (error)
+			return error;
+
+		sg = sg_advance(sg, msb->page_size);
+		*sucessfuly_read += msb->page_size;
+
+		page++;
+		if (page == msb->pages_in_block) {
+			page = 0;
+			lba++;
+		}
+	}
+	return 0;
+}
+
+static int msb_io_thread(void *data)
+{
+	struct msb_data *msb = data;
+	int page, error, len;
+	sector_t lba;
+	unsigned long flags;
+
+	dbg("IO: thread started");
+
+	while (1) {
+
+		if (kthread_should_stop()) {
+			if (msb->req)
+				blk_requeue_request(msb->queue, msb->req);
+			break;
+		}
+
+		spin_lock_irqsave(&msb->q_lock, flags);
+
+		if (msb->need_flush_cache) {
+			msb->need_flush_cache = false;
+			spin_unlock_irqrestore(&msb->q_lock, flags);
+			msb_cache_flush(msb);
+			continue;
+		}
+
+		if (!msb->req) {
+			msb->req = blk_fetch_request(msb->queue);
+
+			if (!msb->req) {
+				dbg_verbose("IO: no more requests, sleeping");
+				set_current_state(TASK_INTERRUPTIBLE);
+				spin_unlock_irqrestore(&msb->q_lock, flags);
+				schedule();
+				dbg_verbose("IO: thread woken up");
+				continue;
+			}
+		}
+
+		spin_unlock_irqrestore(&msb->q_lock, flags);
+
+		/* If card was removed meanwhile */
+		if (!msb->req)
+			continue;
+
+		/* process the request */
+		dbg_verbose("IO: thread processing new request");
+		blk_rq_map_sg(msb->queue, msb->req, msb->req_sg);
+
+		lba = blk_rq_pos(msb->req);
+
+		sector_div(lba, msb->page_size / 512);
+		page = do_div(lba, msb->pages_in_block);
+
+		if (rq_data_dir(msb->req) == READ)
+			error = msb_do_read_request(
+					msb, lba, page, msb->req_sg, &len);
+		else
+			error = msb_do_write_request(
+					msb, lba, page, msb->req_sg, &len);
+
+		spin_lock_irqsave(&msb->q_lock, flags);
+
+		if (len)
+			if (!__blk_end_request(msb->req, 0, len))
+				msb->req = NULL;
+
+		if (error && msb->req) {
+			dbg_verbose("IO: ending one sector "
+					"of the request with error");
+			if (!__blk_end_request(msb->req, error, msb->page_size))
+				msb->req = NULL;
+		}
+
+		if (msb->req)
+			dbg_verbose("IO: request still pending");
+
+		spin_unlock_irqrestore(&msb->q_lock, flags);
+	}
+	return 0;
+}
+
+static DEFINE_IDR(msb_disk_idr);
+static DEFINE_MUTEX(msb_disk_lock);
+
+static int msb_bd_open(struct block_device *bdev, fmode_t mode)
+{
+	struct gendisk *disk = bdev->bd_disk;
+	struct msb_data *msb = disk->private_data;
+
+	dbg_verbose("block device open");
+
+	mutex_lock(&msb_disk_lock);
+
+	if (msb && msb->card)
+		msb->usage_count++;
+
+	mutex_unlock(&msb_disk_lock);
+	return 0;
+}
+
+static void msb_data_clear(struct msb_data *msb)
+{
+	kfree(msb->boot_page);
+	kfree(msb->used_blocks_bitmap);
+	kfree(msb->lba_to_pba_table);
+	kfree(msb->cache);
+	msb->card = NULL;
+}
+
+static int msb_disk_release(struct gendisk *disk)
+{
+	struct msb_data *msb = disk->private_data;
+	int disk_id = MINOR(disk_devt(disk)) >> MS_BLOCK_PART_SHIFT;
+
+	dbg_verbose("block device release");
+
+	mutex_lock(&msb_disk_lock);
+
+	if (msb) {
+		if (msb->usage_count)
+			msb->usage_count--;
+
+		if (!msb->usage_count) {
+			kfree(msb);
+			disk->private_data = NULL;
+			idr_remove(&msb_disk_idr, disk_id);
+			put_disk(disk);
+		}
+	}
+	mutex_unlock(&msb_disk_lock);
+	return 0;
+}
+
+static int msb_bd_release(struct gendisk *disk, fmode_t mode)
+{
+	return msb_disk_release(disk);
+}
+
+static int msb_bd_getgeo(struct block_device *bdev,
+				 struct hd_geometry *geo)
+{
+	struct msb_data *msb = bdev->bd_disk->private_data;
+	*geo = msb->geometry;
+	return 0;
+}
+
+static int msb_prepare_req(struct request_queue *q, struct request *req)
+{
+	if (req->cmd_type != REQ_TYPE_FS &&
+				req->cmd_type != REQ_TYPE_BLOCK_PC) {
+		blk_dump_rq_flags(req, "MS unsupported request");
+		return BLKPREP_KILL;
+	}
+	req->cmd_flags |= REQ_DONTPREP;
+	return BLKPREP_OK;
+}
+
+static void msb_submit_req(struct request_queue *q)
+{
+	struct memstick_dev *card = q->queuedata;
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct request *req = NULL;
+
+	dbg_verbose("Submit request");
+
+	if (msb->card_dead) {
+		dbg("Refusing requests on removed card");
+
+		WARN_ON(msb->io_thread);
+
+		while ((req = blk_fetch_request(q)) != NULL)
+			__blk_end_request_all(req, -ENODEV);
+		return;
+	}
+
+	if (msb->req)
+		return;
+
+	if (msb->io_thread)
+		wake_up_process(msb->io_thread);
+}
+
+static int msb_check_card(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	return (msb->card_dead == 0);
+}
+
+static void msb_stop(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	unsigned long flags;
+	struct task_struct *io_thread;
+
+	dbg("Stopping all msblock IO");
+
+	/* Just stop the IO thread.
+	   Be carefull not to race against submit_request
+	   If it is called, all pending requests will be processed by
+	   the IO thread as soon as msb_start is called */
+
+	spin_lock_irqsave(&msb->q_lock, flags);
+	blk_stop_queue(msb->queue);
+	io_thread = msb->io_thread;
+	msb->io_thread = NULL;
+	spin_unlock_irqrestore(&msb->q_lock, flags);
+
+	del_timer_sync(&msb->cache_flush_timer);
+
+	if (io_thread)
+		kthread_stop(io_thread);
+}
+
+static void msb_start(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	unsigned long flags;
+	int disk_id = MINOR(disk_devt(msb->disk)) >> MS_BLOCK_PART_SHIFT;
+
+	dbg("Resuming IO from msblock");
+
+	spin_lock_irqsave(&msb->q_lock, flags);
+	if (msb->io_thread || msb->card_dead) {
+		spin_unlock_irqrestore(&msb->q_lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&msb->q_lock, flags);
+
+	/* Kick cache flush anyway, its harmless */
+	msb->need_flush_cache = true;
+
+	msb->io_thread = kthread_run(msb_io_thread, msb, "kms_block%d",
+		disk_id);
+
+	spin_lock_irqsave(&msb->q_lock, flags);
+	blk_start_queue(msb->queue);
+	spin_unlock_irqrestore(&msb->q_lock, flags);
+}
+
+static const struct block_device_operations msb_bdops = {
+	.open    = msb_bd_open,
+	.release = msb_bd_release,
+	.getgeo  = msb_bd_getgeo,
+	.owner   = THIS_MODULE
+};
+
+/* Registers the block device */
+static int msb_init_disk(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct memstick_host *host = card->host;
+	int rc, disk_id;
+	u64 limit = BLK_BOUNCE_HIGH;
+	unsigned long capacity;
+
+	if (host->dev.dma_mask && *(host->dev.dma_mask))
+		limit = *(host->dev.dma_mask);
+
+	mutex_lock(&msb_disk_lock);
+
+	if (!idr_pre_get(&msb_disk_idr, GFP_KERNEL)) {
+		mutex_unlock(&msb_disk_lock);
+		return -ENOMEM;
+	}
+
+	rc = idr_get_new(&msb_disk_idr, card, &disk_id);
+	mutex_unlock(&msb_disk_lock);
+
+	if (rc)
+		return rc;
+
+	if ((disk_id << MS_BLOCK_PART_SHIFT) > 255) {
+		rc = -ENOSPC;
+		goto out_release_id;
+	}
+
+	msb->disk = alloc_disk(1 << MS_BLOCK_PART_SHIFT);
+	if (!msb->disk) {
+		rc = -ENOMEM;
+		goto out_release_id;
+	}
+
+	msb->queue = blk_init_queue(msb_submit_req, &msb->q_lock);
+	if (!msb->queue) {
+		rc = -ENOMEM;
+		goto out_put_disk;
+	}
+
+	msb->queue->queuedata = card;
+	blk_queue_prep_rq(msb->queue, msb_prepare_req);
+
+	blk_queue_bounce_limit(msb->queue, limit);
+	blk_queue_max_hw_sectors(msb->queue, MS_BLOCK_MAX_PAGES);
+	blk_queue_max_segments(msb->queue, MS_BLOCK_MAX_SEGS);
+	blk_queue_max_segment_size(msb->queue,
+				   MS_BLOCK_MAX_PAGES * msb->page_size);
+	msb->disk->major = major;
+	msb->disk->first_minor = disk_id << MS_BLOCK_PART_SHIFT;
+	msb->disk->fops = &msb_bdops;
+	msb->usage_count = 1;
+	msb->disk->private_data = msb;
+	msb->disk->queue = msb->queue;
+	msb->disk->driverfs_dev = &card->dev;
+	sg_init_table(msb->req_sg, MS_BLOCK_MAX_SEGS+1);
+
+	sprintf(msb->disk->disk_name, "msblk%d", disk_id);
+
+	blk_queue_logical_block_size(msb->queue, msb->page_size);
+
+	capacity = msb->pages_in_block * msb->logical_block_count;
+	capacity *= (msb->page_size / 512);
+
+	set_capacity(msb->disk, capacity);
+	dbg("Set total disk size to %lu sectors", capacity);
+
+	if (msb->read_only)
+		set_disk_ro(msb->disk, 1);
+
+	msb_start(card);
+	add_disk(msb->disk);
+	dbg("Disk added");
+	return 0;
+
+out_put_disk:
+	put_disk(msb->disk);
+out_release_id:
+	mutex_lock(&msb_disk_lock);
+	idr_remove(&msb_disk_idr, disk_id);
+	mutex_unlock(&msb_disk_lock);
+	return rc;
+}
+
+static int msb_probe(struct memstick_dev *card)
+{
+	struct msb_data *msb;
+	int rc = 0;
+
+	msb = kzalloc(sizeof(struct msb_data), GFP_KERNEL);
+	if (!msb)
+		return -ENOMEM;
+	memstick_set_drvdata(card, msb);
+	msb->card = card;
+	spin_lock_init(&msb->q_lock);
+
+	rc = msb_init_card(card);
+	if (rc)
+		goto out_free;
+
+	rc = msb_init_disk(card);
+	if (!rc) {
+		card->check = msb_check_card;
+		card->stop = msb_stop;
+		card->start = msb_start;
+		return 0;
+	}
+out_free:
+	memstick_set_drvdata(card, NULL);
+	msb_data_clear(msb);
+	kfree(msb);
+	return rc;
+}
+
+static void msb_remove(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	unsigned long flags;
+
+	if (msb->io_thread)
+		msb_stop(card);
+
+	dbg("Removing the disk device");
+
+	/* Take care of unhandled + new requests from now on */
+	spin_lock_irqsave(&msb->q_lock, flags);
+	msb->card_dead = true;
+	blk_start_queue(msb->queue);
+	spin_unlock_irqrestore(&msb->q_lock, flags);
+
+	/* Remove the disk */
+	del_gendisk(msb->disk);
+	blk_cleanup_queue(msb->queue);
+	msb->queue = NULL;
+
+	mutex_lock(&msb_disk_lock);
+	msb_data_clear(msb);
+	mutex_unlock(&msb_disk_lock);
+
+	msb_disk_release(msb->disk);
+	memstick_set_drvdata(card, NULL);
+}
+
+#ifdef CONFIG_PM
+
+static int msb_suspend(struct memstick_dev *card, pm_message_t state)
+{
+	msb_stop(card);
+	return 0;
+}
+
+static int msb_resume(struct memstick_dev *card)
+{
+	struct msb_data *msb = memstick_get_drvdata(card);
+	struct msb_data *new_msb = NULL;
+	bool card_dead = true;
+
+#ifndef CONFIG_MEMSTICK_UNSAFE_RESUME
+	msb->card_dead = true;
+	return 0;
+#endif
+	mutex_lock(&card->host->lock);
+
+	new_msb = kzalloc(sizeof(struct msb_data), GFP_KERNEL);
+	if (!new_msb)
+		goto out;
+
+	new_msb->card = card;
+	memstick_set_drvdata(card, new_msb);
+	spin_lock_init(&new_msb->q_lock);
+
+	if (msb_init_card(card))
+		goto out;
+
+	if (msb->block_size != new_msb->block_size)
+		goto out;
+
+	if (memcmp(msb->boot_page, new_msb->boot_page,
+					sizeof(struct ms_boot_page)))
+		goto out;
+
+	if (msb->logical_block_count != new_msb->logical_block_count ||
+		memcmp(msb->lba_to_pba_table, new_msb->lba_to_pba_table,
+						msb->logical_block_count))
+		goto out;
+
+	if (msb->block_count != new_msb->block_count ||
+		memcmp(msb->used_blocks_bitmap, new_msb->used_blocks_bitmap,
+							msb->block_count / 8))
+		goto out;
+
+	card_dead = false;
+out:
+	if (card_dead)
+		dbg("Card was removed/replaced during suspend");
+
+	msb->card_dead = card_dead;
+	memstick_set_drvdata(card, msb);
+
+	if (new_msb) {
+		msb_data_clear(new_msb);
+		kfree(new_msb);
+	}
+
+	msb_start(card);
+	mutex_unlock(&card->host->lock);
+	return 0;
+}
+#else
+
+#define msb_suspend NULL
+#define msb_resume NULL
+
+#endif /* CONFIG_PM */
+
+static struct memstick_device_id msb_id_tbl[] = {
+	{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+	 MEMSTICK_CLASS_FLASH},
+
+	{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+	 MEMSTICK_CLASS_ROM},
+
+	{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+	 MEMSTICK_CLASS_RO},
+
+	{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+	 MEMSTICK_CLASS_WP},
+
+	{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_DUO, MEMSTICK_CATEGORY_STORAGE_DUO,
+	 MEMSTICK_CLASS_DUO},
+	{}
+};
+MODULE_DEVICE_TABLE(memstick, msb_id_tbl);
+
+
+static struct memstick_driver msb_driver = {
+	.driver = {
+		.name  = DRIVER_NAME,
+		.owner = THIS_MODULE
+	},
+	.id_table = msb_id_tbl,
+	.probe    = msb_probe,
+	.remove   = msb_remove,
+	.suspend  = msb_suspend,
+	.resume   = msb_resume
+};
+
+static int __init msb_init(void)
+{
+	int rc = -ENOMEM;
+
+	rc = register_blkdev(major, DRIVER_NAME);
+	if (rc < 0) {
+		printk(KERN_ERR DRIVER_NAME ": failed to register "
+		       "major %d, error %d\n", major, rc);
+		return rc;
+	}
+	if (!major)
+		major = rc;
+
+	rc = memstick_register_driver(&msb_driver);
+	if (rc)
+		unregister_blkdev(major, DRIVER_NAME);
+	return rc;
+}
+
+static void __exit msb_exit(void)
+{
+	memstick_unregister_driver(&msb_driver);
+	unregister_blkdev(major, DRIVER_NAME);
+	idr_destroy(&msb_disk_idr);
+}
+
+module_init(msb_init);
+module_exit(msb_exit);
+
+module_param(major, int, S_IRUGO);
+MODULE_PARM_DESC(major, "Major to use for block device (default auto)");
+
+module_param(cache_flush_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(cache_flush_timeout,
+				"Cache flush timeout in msec (1000 default)");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0-3)");
+
+module_param(verify_writes, bool, S_IRUGO);
+MODULE_PARM_DESC(verify_writes, "Read back and check all data that is written");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Dubov");
+MODULE_AUTHOR("Maxim Levitsky");
+MODULE_DESCRIPTION("Sony MemoryStick block device driver");
diff --git a/drivers/memstick/core/ms_block.h b/drivers/memstick/core/ms_block.h
new file mode 100644
index 0000000..5e5fa57
--- /dev/null
+++ b/drivers/memstick/core/ms_block.h
@@ -0,0 +1,229 @@
+/*
+ *  ms_block.h - Sony MemoryStick (legacy) storage support
+ *
+ *  Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
+ *  Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Special thanks to Carlos Corbacho for providing various MemoryStick cards
+ * that made this driver possible.
+ *
+ */
+
+#ifndef MS_BLOCK_NEW_H
+#define MS_BLOCK_NEW_H
+
+#define MS_BLOCK_MAX_SEGS      32
+#define MS_BLOCK_MAX_PAGES     ((2 << 16) - 1)
+
+#define MS_BLOCK_MAX_BOOT_ADDR 0x000c
+#define MS_BLOCK_BOOT_ID       0x0001
+#define MS_BLOCK_INVALID       0xffff
+#define MS_MAX_ZONES           16
+#define MS_BLOCKS_IN_ZONE      512
+
+#define MS_BLOCK_MAP_LINE_SZ   16
+#define MS_BLOCK_PART_SHIFT    3
+
+
+#define MEMSTICK_UNCORR_ERROR (MEMSTICK_STATUS1_UCFG | \
+		MEMSTICK_STATUS1_UCEX | MEMSTICK_STATUS1_UCDT)
+
+#define MEMSTICK_CORR_ERROR (MEMSTICK_STATUS1_FGER | MEMSTICK_STATUS1_EXER | \
+	MEMSTICK_STATUS1_DTER)
+
+#define MEMSTICK_INT_ERROR (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)
+
+#define MEMSTICK_OVERWRITE_FLAG_NORMAL \
+	(MEMSTICK_OVERWRITE_PGST1 | \
+	MEMSTICK_OVERWRITE_PGST0  | \
+	MEMSTICK_OVERWRITE_BKST)
+
+#define MEMSTICK_OV_PG_NORMAL \
+	(MEMSTICK_OVERWRITE_PGST1 | MEMSTICK_OVERWRITE_PGST0)
+
+#define MEMSTICK_MANAGMENT_FLAG_NORMAL \
+	(MEMSTICK_MANAGEMENT_SYSFLG |  \
+	MEMSTICK_MANAGEMENT_SCMS1   |  \
+	MEMSTICK_MANAGEMENT_SCMS0)     \
+
+struct ms_boot_header {
+	unsigned short block_id;
+	unsigned short format_reserved;
+	unsigned char  reserved0[184];
+	unsigned char  data_entry;
+	unsigned char  reserved1[179];
+} __packed;
+
+
+struct ms_system_item {
+	unsigned int  start_addr;
+	unsigned int  data_size;
+	unsigned char data_type_id;
+	unsigned char reserved[3];
+} __packed;
+
+struct ms_system_entry {
+	struct ms_system_item disabled_block;
+	struct ms_system_item cis_idi;
+	unsigned char         reserved[24];
+} __packed;
+
+struct ms_boot_attr_info {
+	unsigned char      memorystick_class;
+	unsigned char      format_unique_value1;
+	unsigned short     block_size;
+	unsigned short     number_of_blocks;
+	unsigned short     number_of_effective_blocks;
+	unsigned short     page_size;
+	unsigned char      extra_data_size;
+	unsigned char      format_unique_value2;
+	unsigned char      assembly_time[8];
+	unsigned char      format_unique_value3;
+	unsigned char      serial_number[3];
+	unsigned char      assembly_manufacturer_code;
+	unsigned char      assembly_model_code[3];
+	unsigned short     memory_manufacturer_code;
+	unsigned short     memory_device_code;
+	unsigned short     implemented_capacity;
+	unsigned char      format_unique_value4[2];
+	unsigned char      vcc;
+	unsigned char      vpp;
+	unsigned short     controller_number;
+	unsigned short     controller_function;
+	unsigned char      reserved0[9];
+	unsigned char      transfer_supporting;
+	unsigned short     format_unique_value5;
+	unsigned char      format_type;
+	unsigned char      memorystick_application;
+	unsigned char      device_type;
+	unsigned char      reserved1[22];
+	unsigned char      format_uniqure_value6[2];
+	unsigned char      reserved2[15];
+} __packed;
+
+struct ms_cis_idi {
+	unsigned short general_config;
+	unsigned short logical_cylinders;
+	unsigned short reserved0;
+	unsigned short logical_heads;
+	unsigned short track_size;
+	unsigned short page_size;
+	unsigned short pages_per_track;
+	unsigned short msw;
+	unsigned short lsw;
+	unsigned short reserved1;
+	unsigned char  serial_number[20];
+	unsigned short buffer_type;
+	unsigned short buffer_size_increments;
+	unsigned short long_command_ecc;
+	unsigned char  firmware_version[28];
+	unsigned char  model_name[18];
+	unsigned short reserved2[5];
+	unsigned short pio_mode_number;
+	unsigned short dma_mode_number;
+	unsigned short field_validity;
+	unsigned short current_logical_cylinders;
+	unsigned short current_logical_heads;
+	unsigned short current_pages_per_track;
+	unsigned int   current_page_capacity;
+	unsigned short mutiple_page_setting;
+	unsigned int   addressable_pages;
+	unsigned short single_word_dma;
+	unsigned short multi_word_dma;
+	unsigned char  reserved3[128];
+} __packed;
+
+
+struct ms_boot_page {
+	struct ms_boot_header    header;
+	struct ms_system_entry   entry;
+	struct ms_boot_attr_info attr;
+} __packed;
+
+struct msb_data {
+	unsigned int			usage_count;
+	struct memstick_dev		*card;
+	struct gendisk			*disk;
+	struct request_queue		*queue;
+	spinlock_t			q_lock;
+	struct hd_geometry		geometry;
+	struct attribute_group		attr_group;
+	struct request			*req;
+
+	/* IO */
+	struct task_struct		*io_thread;
+	bool				card_dead;
+
+	/* Media properties */
+	struct ms_boot_page		*boot_page;
+	u16				boot_block_locations[2];
+	int				boot_block_count;
+
+	bool				read_only;
+	unsigned short			page_size;
+	int				block_size;
+	int				pages_in_block;
+	int				zone_count;
+	int				block_count;
+	int				logical_block_count;
+
+	/* FTL tables */
+	unsigned long			*used_blocks_bitmap;
+	unsigned long			*erased_blocks_bitmap;
+	u16				*lba_to_pba_table;
+	int				free_block_count[MS_MAX_ZONES];
+	bool				ftl_initialized;
+
+	/* Cache */
+	unsigned char			*cache;
+	unsigned long			valid_cache_bitmap;
+	int				cache_block_lba;
+	bool				need_flush_cache;
+	struct timer_list		cache_flush_timer;
+
+
+	struct scatterlist		req_sg[MS_BLOCK_MAX_SEGS+1];
+	unsigned char			*block_buffer;
+
+	/* handler's local data */
+	u8				command_value;
+	bool				command_need_oob;
+	struct scatterlist		*current_sg;
+	int				sg_offset;
+
+	struct ms_register		regs;
+	int				current_page;
+};
+
+
+struct chs_entry {
+	unsigned long size;
+	unsigned char sec;
+	unsigned short cyl;
+	unsigned char head;
+};
+
+static int msb_reset(struct msb_data *msb, bool full);
+
+
+#define DRIVER_NAME "ms_block"
+
+#define ms_printk(format, ...) \
+	printk(KERN_INFO DRIVER_NAME ": " format "\n", ## __VA_ARGS__)
+
+#define __dbg(level, format, ...) \
+	do { \
+		if (debug >= level) \
+			printk(KERN_DEBUG DRIVER_NAME \
+				": " format "\n", ## __VA_ARGS__); \
+	} while (0)
+
+
+#define dbg(format, ...)		__dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...)	__dbg(2, format, ## __VA_ARGS__)
+
+#endif
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* [PATCH 29/29] memstick: Add driver for Ricoh R5C592 Card reader.
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (27 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 28/29] memstick: add support for legacy memorysticks Maxim Levitsky
@ 2010-10-22 23:53 ` Maxim Levitsky
  2010-10-25  2:01 ` [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
  29 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-22 23:53 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 MAINTAINERS                    |    5 +
 drivers/memstick/host/Kconfig  |   12 +
 drivers/memstick/host/Makefile |    1 +
 drivers/memstick/host/r592.c   |  878 ++++++++++++++++++++++++++++++++++++++++
 drivers/memstick/host/r592.h   |  175 ++++++++
 5 files changed, 1071 insertions(+), 0 deletions(-)
 create mode 100644 drivers/memstick/host/r592.c
 create mode 100644 drivers/memstick/host/r592.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 71df8db..4ff3fce 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4919,6 +4919,11 @@ S:	Maintained
 F:	drivers/mtd/nand/r852.c
 F:	drivers/mtd/nand/r852.h
 
+RICOH R5C592 MEMORYSTICK DRIVER
+M:	Maxim Levitsky <maximlevitsky@gmail.com>
+S:	Maintained
+F:	drivers/memstick/host/r592.*
+
 RISCOM8 DRIVER
 S:	Orphan
 F:	Documentation/serial/riscom8.txt
diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig
index 4ce5c8d..cc0997a 100644
--- a/drivers/memstick/host/Kconfig
+++ b/drivers/memstick/host/Kconfig
@@ -30,3 +30,15 @@ config MEMSTICK_JMICRON_38X
 
           To compile this driver as a module, choose M here: the
 	  module will be called jmb38x_ms.
+
+config MEMSTICK_R592
+	tristate "Ricoh R5C592 MemoryStick interface support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && PCI
+
+	help
+	  Say Y here if you want to be able to access MemoryStick cards with
+	  the Ricoh R5C592 MemoryStick card reader (which is part of 5 in one
+		multifunction reader)
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called r592.
diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile
index 12530e4..ad63c16 100644
--- a/drivers/memstick/host/Makefile
+++ b/drivers/memstick/host/Makefile
@@ -8,3 +8,4 @@ endif
 
 obj-$(CONFIG_MEMSTICK_TIFM_MS)		+= tifm_ms.o
 obj-$(CONFIG_MEMSTICK_JMICRON_38X)	+= jmb38x_ms.o
+obj-$(CONFIG_MEMSTICK_R592)		+= r592.o
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c
new file mode 100644
index 0000000..1ec0085
--- /dev/null
+++ b/drivers/memstick/host/r592.c
@@ -0,0 +1,878 @@
+/*
+ * Copyright (C) 2010 - Maxim Levitsky
+ * driver for Ricoh memstick readers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/freezer.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <asm/byteorder.h>
+#include <linux/swab.h>
+#include "r592.h"
+
+static int enable_dma = 1;
+static int debug;
+
+
+/* Read a register*/
+static inline u32 r592_read_reg(struct r592_device *dev, int address)
+{
+	u32 value = readl(dev->mmio + address);
+	dbg_reg("reg #%02d == 0x%08x", address, value);
+	return value;
+}
+
+/* Write a register */
+static inline void r592_write_reg(struct r592_device *dev,
+							int address, u32 value)
+{
+	dbg_reg("reg #%02d <- 0x%08x", address, value);
+	writel(value, dev->mmio + address);
+}
+
+/* Reads a big endian DWORD register */
+static inline u32 r592_read_reg_raw_be(struct r592_device *dev, int address)
+{
+	u32 value = __raw_readl(dev->mmio + address);
+	dbg_reg("reg #%02d == 0x%08x", address, value);
+	return be32_to_cpu(value);
+}
+
+/* Writes a big endian DWORD register */
+static inline void r592_write_reg_raw_be(struct r592_device *dev,
+							int address, u32 value)
+{
+	dbg_reg("reg #%02d <- 0x%08x", address, value);
+	__raw_writel(cpu_to_be32(value), dev->mmio + address);
+}
+
+/* Set specific bits in a register (little endian) */
+static inline void r592_set_reg_mask(struct r592_device *dev,
+							int address, u32 mask)
+{
+	u32 reg = readl(dev->mmio + address);
+	dbg_reg("reg #%02d |= 0x%08x (old =0x%08x)", address, mask, reg);
+	writel(reg | mask , dev->mmio + address);
+}
+
+/* Clear specific bits in a register (little endian) */
+static inline void r592_clear_reg_mask(struct r592_device *dev,
+						int address, u32 mask)
+{
+	u32 reg = readl(dev->mmio + address);
+	dbg_reg("reg #%02d &= 0x%08x (old = 0x%08x, mask = 0x%08x)",
+						address, ~mask, reg, mask);
+	writel(reg & ~mask, dev->mmio + address);
+}
+
+
+/* Wait for status bits while checking for errors */
+static int r592_wait_status(struct r592_device *dev, u32 mask, u32 wanted_mask)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+	u32 reg = r592_read_reg(dev, R592_STATUS);
+
+	if ((reg & mask) == wanted_mask)
+		return 0;
+
+	while (time_before(jiffies, timeout)) {
+
+		reg = r592_read_reg(dev, R592_STATUS);
+
+		if ((reg & mask) == wanted_mask)
+			return 0;
+
+		if (reg & (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR))
+			return -EIO;
+
+		cpu_relax();
+	}
+	return -ETIME;
+}
+
+
+/* Enable/disable device */
+static int r592_enable_device(struct r592_device *dev, bool enable)
+{
+	dbg("%sabling the device", enable ? "en" : "dis");
+
+	if (enable) {
+
+		/* Power up the card */
+		r592_write_reg(dev, R592_POWER, R592_POWER_0 | R592_POWER_1);
+
+		/* Perform a reset */
+		r592_set_reg_mask(dev, R592_IO, R592_IO_RESET);
+
+		msleep(100);
+	} else
+		/* Power down the card */
+		r592_write_reg(dev, R592_POWER, 0);
+
+	return 0;
+}
+
+/* Set serial/parallel mode */
+static int r592_set_mode(struct r592_device *dev, bool parallel_mode)
+{
+	if (!parallel_mode) {
+		dbg("switching to serial mode");
+
+		/* Set serial mode */
+		r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_SERIAL);
+
+		r592_clear_reg_mask(dev, R592_POWER, R592_POWER_20);
+
+	} else {
+		dbg("switching to parallel mode");
+
+		/* This setting should be set _before_ switch TPC */
+		r592_set_reg_mask(dev, R592_POWER, R592_POWER_20);
+
+		r592_clear_reg_mask(dev, R592_IO,
+			R592_IO_SERIAL1 | R592_IO_SERIAL2);
+
+		/* Set the parallel mode now */
+		r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_PARALLEL);
+	}
+
+	dev->parallel_mode = parallel_mode;
+	return 0;
+}
+
+/* Perform a controller reset without powering down the card */
+static void r592_host_reset(struct r592_device *dev)
+{
+	r592_set_reg_mask(dev, R592_IO, R592_IO_RESET);
+	msleep(100);
+	r592_set_mode(dev, dev->parallel_mode);
+}
+
+/* Disable all hardware interrupts */
+static void r592_clear_interrupts(struct r592_device *dev)
+{
+	/* Disable & ACK all interrupts */
+	r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK);
+	r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK);
+}
+
+/* Tests if there is an CRC error */
+static int r592_test_io_error(struct r592_device *dev)
+{
+	if (!(r592_read_reg(dev, R592_STATUS) &
+		(R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR)))
+		return 0;
+
+	return -EIO;
+}
+
+/* Ensure that FIFO is ready for use */
+static int r592_test_fifo_empty(struct r592_device *dev)
+{
+	if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY)
+		return 0;
+
+	dbg("FIFO not ready, trying to reset the device");
+	r592_host_reset(dev);
+
+	if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY)
+		return 0;
+
+	message("FIFO still not ready, giving up");
+	return -EIO;
+}
+
+/* Activates the DMA transfer from to FIFO */
+static void r592_start_dma(struct r592_device *dev, bool is_write)
+{
+	unsigned long flags;
+	u32 reg;
+	spin_lock_irqsave(&dev->irq_lock, flags);
+
+	/* Ack interrupts (just in case) + enable them */
+	r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK);
+	r592_set_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK);
+
+	/* Set DMA address */
+	r592_write_reg(dev, R592_FIFO_DMA, sg_dma_address(&dev->req->sg));
+
+	/* Enable the DMA */
+	reg = r592_read_reg(dev, R592_FIFO_DMA_SETTINGS);
+	reg |= R592_FIFO_DMA_SETTINGS_EN;
+
+	if (!is_write)
+		reg |= R592_FIFO_DMA_SETTINGS_DIR;
+	else
+		reg &= ~R592_FIFO_DMA_SETTINGS_DIR;
+	r592_write_reg(dev, R592_FIFO_DMA_SETTINGS, reg);
+
+	spin_unlock_irqrestore(&dev->irq_lock, flags);
+}
+
+/* Cleanups DMA related settings */
+static void r592_stop_dma(struct r592_device *dev, int error)
+{
+	r592_clear_reg_mask(dev, R592_FIFO_DMA_SETTINGS,
+		R592_FIFO_DMA_SETTINGS_EN);
+
+	/* This is only a precation */
+	r592_write_reg(dev, R592_FIFO_DMA,
+			dev->dummy_dma_page_physical_address);
+
+	r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK);
+	r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK);
+	dev->dma_error = error;
+}
+
+/* Test if hardware supports DMA */
+static void r592_check_dma(struct r592_device *dev)
+{
+	dev->dma_capable = enable_dma &&
+		(r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) &
+			R592_FIFO_DMA_SETTINGS_CAP);
+}
+
+/* Transfers fifo contents in/out using DMA */
+static int r592_transfer_fifo_dma(struct r592_device *dev)
+{
+	int len, sg_count;
+	bool is_write;
+
+	if (!dev->dma_capable || !dev->req->long_data)
+		return -EINVAL;
+
+	len = dev->req->sg.length;
+	is_write = dev->req->data_dir == WRITE;
+
+	if (len != R592_LFIFO_SIZE)
+		return -EINVAL;
+
+	dbg_verbose("doing dma transfer");
+
+	dev->dma_error = 0;
+	INIT_COMPLETION(dev->dma_done);
+
+	/* TODO: hidden assumption about nenth beeing always 1 */
+	sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ?
+		PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+	if (sg_count != 1 ||
+			(sg_dma_len(&dev->req->sg) < dev->req->sg.length)) {
+		message("problem in dma_map_sg");
+		return -EIO;
+	}
+
+	r592_start_dma(dev, is_write);
+
+	/* Wait for DMA completion */
+	if (!wait_for_completion_timeout(
+			&dev->dma_done, msecs_to_jiffies(1000))) {
+		message("DMA timeout");
+		r592_stop_dma(dev, -ETIMEDOUT);
+	}
+
+	dma_unmap_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ?
+		PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+
+	return dev->dma_error;
+}
+
+/*
+ * Writes the FIFO in 4 byte chunks.
+ * If length isn't 4 byte aligned, rest of the data if put to a fifo
+ * to be written later
+ * Use r592_flush_fifo_write to flush that fifo when writing for the
+ * last time
+ */
+static void r592_write_fifo_pio(struct r592_device *dev,
+					unsigned char *buffer, int len)
+{
+	/* flush spill from former write */
+	if (!kfifo_is_empty(&dev->pio_fifo)) {
+
+		u8 tmp[4] = {0};
+		int copy_len = kfifo_in(&dev->pio_fifo, buffer, len);
+
+		if (!kfifo_is_full(&dev->pio_fifo))
+			return;
+		len -= copy_len;
+		buffer += copy_len;
+
+		copy_len = kfifo_out(&dev->pio_fifo, tmp, 4);
+		WARN_ON(copy_len != 4);
+		r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)tmp);
+	}
+
+	WARN_ON(!kfifo_is_empty(&dev->pio_fifo));
+
+	/* write full dwords */
+	while (len >= 4) {
+		r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer);
+		buffer += 4;
+		len -= 4;
+	}
+
+	/* put remaining bytes to the spill */
+	if (len)
+		kfifo_in(&dev->pio_fifo, buffer, len);
+}
+
+/* Flushes the temporary FIFO used to make aligned DWORD writes */
+static void r592_flush_fifo_write(struct r592_device *dev)
+{
+	u8 buffer[4] = { 0 };
+	int len;
+
+	if (kfifo_is_empty(&dev->pio_fifo))
+		return;
+
+	len = kfifo_out(&dev->pio_fifo, buffer, 4);
+	r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer);
+}
+
+/*
+ * Read a fifo in 4 bytes chunks.
+ * If input doesn't fit the buffer, it places bytes of last dword in spill
+ * buffer, so that they don't get lost on last read, just throw these away.
+ */
+static void r592_read_fifo_pio(struct r592_device *dev,
+						unsigned char *buffer, int len)
+{
+	u8 tmp[4];
+
+	/* Read from last spill */
+	if (!kfifo_is_empty(&dev->pio_fifo)) {
+		int bytes_copied =
+			kfifo_out(&dev->pio_fifo, buffer, min(4, len));
+		buffer += bytes_copied;
+		len -= bytes_copied;
+
+		if (!kfifo_is_empty(&dev->pio_fifo))
+			return;
+	}
+
+	/* Reads dwords from FIFO */
+	while (len >= 4) {
+		*(u32 *)buffer = r592_read_reg_raw_be(dev, R592_FIFO_PIO);
+		buffer += 4;
+		len -= 4;
+	}
+
+	if (len) {
+		*(u32 *)tmp = r592_read_reg_raw_be(dev, R592_FIFO_PIO);
+		kfifo_in(&dev->pio_fifo, tmp, 4);
+		len -= kfifo_out(&dev->pio_fifo, buffer, len);
+	}
+
+	WARN_ON(len);
+	return;
+}
+
+/* Transfers actual data using PIO. */
+static int r592_transfer_fifo_pio(struct r592_device *dev)
+{
+	unsigned long flags;
+
+	bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS;
+	struct sg_mapping_iter miter;
+
+	kfifo_reset(&dev->pio_fifo);
+
+	if (!dev->req->long_data) {
+		if (is_write) {
+			r592_write_fifo_pio(dev, dev->req->data,
+							dev->req->data_len);
+			r592_flush_fifo_write(dev);
+		} else
+			r592_read_fifo_pio(dev, dev->req->data,
+							dev->req->data_len);
+		return 0;
+	}
+
+	local_irq_save(flags);
+	sg_miter_start(&miter, &dev->req->sg, 1, SG_MITER_ATOMIC |
+		(is_write ? SG_MITER_FROM_SG : SG_MITER_TO_SG));
+
+	/* Do the transfer fifo<->memory*/
+	while (sg_miter_next(&miter))
+		if (is_write)
+			r592_write_fifo_pio(dev, miter.addr, miter.length);
+		else
+			r592_read_fifo_pio(dev, miter.addr, miter.length);
+
+
+	/* Write last few non aligned bytes*/
+	if (is_write)
+		r592_flush_fifo_write(dev);
+
+	sg_miter_stop(&miter);
+	local_irq_restore(flags);
+	return 0;
+}
+
+/* Executes one TPC (data is read/written from small or large fifo) */
+static void r592_execute_tpc(struct r592_device *dev)
+{
+	bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS;
+	int len, error;
+	u32 status, reg;
+
+	if (!dev->req) {
+		message("BUG: tpc execution without request!");
+		return;
+	}
+
+	len = dev->req->long_data ?
+		dev->req->sg.length : dev->req->data_len;
+
+	/* Ensure that FIFO can hold the input data */
+	if (len > R592_LFIFO_SIZE) {
+		message("IO: hardware doesn't support TPCs longer that 512");
+		error = -ENOSYS;
+		goto out;
+	}
+
+	if (!(r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_PRSNT)) {
+		dbg("IO: refusing to send TPC because card is absent");
+		error = -ENODEV;
+		goto out;
+	}
+
+	dbg("IO: executing %s LEN=%d",
+			memstick_debug_get_tpc_name(dev->req->tpc), len);
+
+	/* Set IO direction */
+	if (is_write)
+		r592_set_reg_mask(dev, R592_IO, R592_IO_DIRECTION);
+	else
+		r592_clear_reg_mask(dev, R592_IO, R592_IO_DIRECTION);
+
+
+	error = r592_test_fifo_empty(dev);
+	if (error)
+		goto out;
+
+	/* Transfer write data */
+	if (is_write) {
+		error = r592_transfer_fifo_dma(dev);
+		if (error == -EINVAL)
+			error = r592_transfer_fifo_pio(dev);
+	}
+
+	if (error)
+		goto out;
+
+	/* Trigger the TPC */
+	reg = (len << R592_TPC_EXEC_LEN_SHIFT) |
+		(dev->req->tpc << R592_TPC_EXEC_TPC_SHIFT) |
+			R592_TPC_EXEC_BIG_FIFO;
+
+	r592_write_reg(dev, R592_TPC_EXEC, reg);
+
+	/* Wait for TPC completion */
+	status = R592_STATUS_RDY;
+	if (dev->req->need_card_int)
+		status |= R592_STATUS_CED;
+
+	error = r592_wait_status(dev, status, status);
+	if (error) {
+		message("card didn't respond");
+		goto out;
+	}
+
+	/* Test IO errors */
+	error = r592_test_io_error(dev);
+	if (error) {
+		dbg("IO error");
+		goto out;
+	}
+
+	/* Read data from FIFO */
+	if (!is_write) {
+		error = r592_transfer_fifo_dma(dev);
+		if (error == -EINVAL)
+			error = r592_transfer_fifo_pio(dev);
+	}
+
+	/* read INT reg. This can be shortened with shifts, but that way
+		its more readable */
+	if (dev->parallel_mode && dev->req->need_card_int) {
+
+		dev->req->int_reg = 0;
+		status = r592_read_reg(dev, R592_STATUS);
+
+		if (status & R592_STATUS_P_CMDNACK)
+			dev->req->int_reg |= MEMSTICK_INT_CMDNAK;
+		if (status & R592_STATUS_P_BREQ)
+			dev->req->int_reg |= MEMSTICK_INT_BREQ;
+		if (status & R592_STATUS_P_INTERR)
+			dev->req->int_reg |= MEMSTICK_INT_ERR;
+		if (status & R592_STATUS_P_CED)
+			dev->req->int_reg |= MEMSTICK_INT_CED;
+	}
+
+	if (error)
+		dbg("FIFO read error");
+out:
+	dev->req->error = error;
+	r592_clear_reg_mask(dev, R592_REG_MSC, R592_REG_MSC_LED);
+	return;
+}
+
+/* Main request processing thread */
+static int r592_process_thread(void *data)
+{
+	int error;
+	struct r592_device *dev = (struct r592_device *)data;
+	unsigned long flags;
+
+	while (!kthread_should_stop()) {
+		spin_lock_irqsave(&dev->io_thread_lock, flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		error = memstick_next_req(dev->host, &dev->req);
+		spin_unlock_irqrestore(&dev->io_thread_lock, flags);
+
+		if (error) {
+			if (error == -ENXIO) {
+				dbg_verbose("IO: done IO, sleeping");
+			} else {
+				dbg("IO: unknown error from "
+					"memstick_next_req %d", error);
+			}
+
+			if (kthread_should_stop())
+				set_current_state(TASK_RUNNING);
+
+			schedule();
+		} else {
+			set_current_state(TASK_RUNNING);
+			r592_execute_tpc(dev);
+		}
+	}
+	return 0;
+}
+
+/* Reprogram chip to detect change in card state */
+/* eg, if card is detected, arm it to detect removal, and vice versa */
+static void r592_update_card_detect(struct r592_device *dev)
+{
+	u32 reg = r592_read_reg(dev, R592_REG_MSC);
+	bool card_detected = reg & R592_REG_MSC_PRSNT;
+
+	dbg("update card detect. card state: %s", card_detected ?
+		"present" : "absent");
+
+	reg &= ~((R592_REG_MSC_IRQ_REMOVE | R592_REG_MSC_IRQ_INSERT) << 16);
+
+	if (card_detected)
+		reg |= (R592_REG_MSC_IRQ_REMOVE << 16);
+	else
+		reg |= (R592_REG_MSC_IRQ_INSERT << 16);
+
+	r592_write_reg(dev, R592_REG_MSC, reg);
+}
+
+/* Timer routine that fires 1 second after last card detection event, */
+static void r592_detect_timer(long unsigned int data)
+{
+	struct r592_device *dev = (struct r592_device *)data;
+	r592_update_card_detect(dev);
+	memstick_detect_change(dev->host);
+}
+
+/* Interrupt handler */
+static irqreturn_t r592_irq(int irq, void *data)
+{
+	struct r592_device *dev = (struct r592_device *)data;
+	irqreturn_t ret = IRQ_NONE;
+	u32 reg;
+	u16 irq_enable, irq_status;
+	unsigned long flags;
+	int error;
+
+	spin_lock_irqsave(&dev->irq_lock, flags);
+
+	reg = r592_read_reg(dev, R592_REG_MSC);
+	irq_enable = reg >> 16;
+	irq_status = reg & 0xFFFF;
+
+	/* Ack the interrupts */
+	reg &= ~irq_status;
+	r592_write_reg(dev, R592_REG_MSC, reg);
+
+	/* Get the IRQ status minus bits that aren't enabled */
+	irq_status &= (irq_enable);
+
+	/* Due to limitation of memstick core, we don't look at bits that
+		indicate that card was removed/inserted and/or present */
+	if (irq_status & (R592_REG_MSC_IRQ_INSERT | R592_REG_MSC_IRQ_REMOVE)) {
+
+		bool card_was_added = irq_status & R592_REG_MSC_IRQ_INSERT;
+		ret = IRQ_HANDLED;
+
+		message("IRQ: card %s", card_was_added ? "added" : "removed");
+
+		mod_timer(&dev->detect_timer,
+			jiffies + msecs_to_jiffies(card_was_added ? 500 : 50));
+	}
+
+	if (irq_status &
+		(R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)) {
+		ret = IRQ_HANDLED;
+
+		if (irq_status & R592_REG_MSC_FIFO_DMA_ERR) {
+			message("IRQ: DMA error");
+			error = -EIO;
+		} else {
+			dbg_verbose("IRQ: dma done");
+			error = 0;
+		}
+
+		r592_stop_dma(dev, error);
+		complete(&dev->dma_done);
+	}
+
+	spin_unlock_irqrestore(&dev->irq_lock, flags);
+	return ret;
+}
+
+/* External inteface: set settings */
+static int r592_set_param(struct memstick_host *host,
+			enum memstick_param param, int value)
+{
+	struct r592_device *dev = memstick_priv(host);
+
+	switch (param) {
+	case MEMSTICK_POWER:
+		switch (value) {
+		case MEMSTICK_POWER_ON:
+			return r592_enable_device(dev, true);
+		case MEMSTICK_POWER_OFF:
+			return r592_enable_device(dev, false);
+		default:
+			return -EINVAL;
+		}
+	case MEMSTICK_INTERFACE:
+		switch (value) {
+		case MEMSTICK_SERIAL:
+			return r592_set_mode(dev, 0);
+		case MEMSTICK_PAR4:
+			return r592_set_mode(dev, 1);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+/* External interface: submit requests */
+static void r592_submit_req(struct memstick_host *host)
+{
+	struct r592_device *dev = memstick_priv(host);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->io_thread_lock, flags);
+	if (wake_up_process(dev->io_thread))
+		dbg_verbose("IO thread woken to process requests");
+	spin_unlock_irqrestore(&dev->io_thread_lock, flags);
+}
+
+static const struct pci_device_id r592_pci_id_tbl[] = {
+
+	{ PCI_VDEVICE(RICOH, 0x0592), },
+	{ },
+};
+
+/* Main entry */
+static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int error = -ENOMEM;
+	struct memstick_host *host;
+	struct r592_device *dev;
+
+	/* Allocate memory */
+	host = memstick_alloc_host(sizeof(struct r592_device), &pdev->dev);
+	if (!host)
+		goto error1;
+
+	dev = memstick_priv(host);
+	dev->host = host;
+	dev->pci_dev = pdev;
+	pci_set_drvdata(pdev, dev);
+
+	/* pci initialization */
+	error = pci_enable_device(pdev);
+	if (error)
+		goto error2;
+
+	pci_set_master(pdev);
+	error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (error)
+		goto error3;
+
+	error = pci_request_regions(pdev, DRV_NAME);
+	if (error)
+		goto error3;
+
+	dev->mmio = pci_ioremap_bar(pdev, 0);
+	if (!dev->mmio)
+		goto error4;
+
+	dev->irq = pdev->irq;
+	spin_lock_init(&dev->irq_lock);
+	spin_lock_init(&dev->io_thread_lock);
+	init_completion(&dev->dma_done);
+	INIT_KFIFO(dev->pio_fifo);
+	setup_timer(&dev->detect_timer,
+		r592_detect_timer, (long unsigned int)dev);
+
+	/* Host initialization */
+	host->caps = MEMSTICK_CAP_PAR4;
+	host->request = r592_submit_req;
+	host->set_param = r592_set_param;
+	r592_check_dma(dev);
+
+	dev->io_thread = kthread_run(r592_process_thread, dev, "r592_io");
+	if (IS_ERR(dev->io_thread)) {
+		error = PTR_ERR(dev->io_thread);
+		goto error5;
+	}
+
+	/* This is just a precation, so don't fail */
+	dev->dummy_dma_page = pci_alloc_consistent(pdev, PAGE_SIZE,
+		&dev->dummy_dma_page_physical_address);
+	r592_stop_dma(dev , 0);
+
+	if (request_irq(dev->irq, &r592_irq, IRQF_SHARED,
+			  DRV_NAME, dev))
+		goto error6;
+
+	r592_update_card_detect(dev);
+	if (memstick_add_host(host))
+		goto error7;
+
+	message("driver succesfully loaded");
+	return 0;
+error7:
+	free_irq(dev->irq, dev);
+error6:
+	if (dev->dummy_dma_page)
+		pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page,
+			dev->dummy_dma_page_physical_address);
+
+	kthread_stop(dev->io_thread);
+error5:
+	iounmap(dev->mmio);
+error4:
+	pci_release_regions(pdev);
+error3:
+	pci_disable_device(pdev);
+error2:
+	memstick_free_host(host);
+error1:
+	return error;
+}
+
+static void r592_remove(struct pci_dev *pdev)
+{
+	int error = 0;
+	struct r592_device *dev = pci_get_drvdata(pdev);
+
+	/* Stop the processing thread.
+	That ensures that we won't take any more requests */
+	kthread_stop(dev->io_thread);
+
+	r592_enable_device(dev, false);
+
+	while (!error && dev->req) {
+		dev->req->error = -ETIME;
+		error = memstick_next_req(dev->host, &dev->req);
+	}
+	memstick_remove_host(dev->host);
+
+	free_irq(dev->irq, dev);
+	iounmap(dev->mmio);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	memstick_free_host(dev->host);
+
+	if (dev->dummy_dma_page)
+		pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page,
+			dev->dummy_dma_page_physical_address);
+}
+
+#ifdef CONFIG_PM
+static int r592_suspend(struct device *core_dev)
+{
+	struct pci_dev *pdev = to_pci_dev(core_dev);
+	struct r592_device *dev = pci_get_drvdata(pdev);
+
+	r592_clear_interrupts(dev);
+	memstick_suspend_host(dev->host);
+	del_timer_sync(&dev->detect_timer);
+	return 0;
+}
+
+static int r592_resume(struct device *core_dev)
+{
+	struct pci_dev *pdev = to_pci_dev(core_dev);
+	struct r592_device *dev = pci_get_drvdata(pdev);
+
+	r592_clear_interrupts(dev);
+	r592_enable_device(dev, false);
+	memstick_resume_host(dev->host);
+	r592_update_card_detect(dev);
+	return 0;
+}
+
+SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume);
+#endif
+
+MODULE_DEVICE_TABLE(pci, r592_pci_id_tbl);
+
+static struct pci_driver r852_pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= r592_pci_id_tbl,
+	.probe		= r592_probe,
+	.remove		= r592_remove,
+#ifdef CONFIG_PM
+	.driver.pm	= &r592_pm_ops,
+#endif
+};
+
+static __init int r592_module_init(void)
+{
+	return pci_register_driver(&r852_pci_driver);
+}
+
+static void __exit r592_module_exit(void)
+{
+	pci_unregister_driver(&r852_pci_driver);
+}
+
+module_init(r592_module_init);
+module_exit(r592_module_exit);
+
+module_param(enable_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0-3)");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
+MODULE_DESCRIPTION("Ricoh R5C592 Memstick/Memstick PRO card reader driver");
diff --git a/drivers/memstick/host/r592.h b/drivers/memstick/host/r592.h
new file mode 100644
index 0000000..eee264e
--- /dev/null
+++ b/drivers/memstick/host/r592.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 - Maxim Levitsky
+ * driver for Ricoh memstick readers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef R592_H
+
+#include <linux/memstick.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#include <linux/ctype.h>
+
+/* write to this reg (number,len) triggers TPC execution */
+#define R592_TPC_EXEC			0x00
+#define R592_TPC_EXEC_LEN_SHIFT		16		/* Bits 16..25 are TPC len */
+#define R592_TPC_EXEC_BIG_FIFO		(1 << 26)	/* If bit 26 is set, large fifo is used (reg 48) */
+#define R592_TPC_EXEC_TPC_SHIFT		28		/* Bits 28..31 are the TPC number */
+
+
+/* Window for small TPC fifo (big endian)*/
+/* reads and writes always are done in  8 byte chunks */
+/* Not used in driver, because large fifo does better job */
+#define R592_SFIFO			0x08
+
+
+/* Status register (ms int, small fifo, IO)*/
+#define R592_STATUS			0x10
+							/* Parallel INT bits */
+#define R592_STATUS_P_CMDNACK		(1 << 16)	/* INT reg: NACK (parallel mode) */
+#define R592_STATUS_P_BREQ		(1 << 17)	/* INT reg: card ready (parallel mode)*/
+#define R592_STATUS_P_INTERR		(1 << 18)	/* INT reg: int error (parallel mode)*/
+#define R592_STATUS_P_CED		(1 << 19)	/* INT reg: command done (parallel mode) */
+
+							/* Fifo status */
+#define R592_STATUS_SFIFO_FULL		(1 << 20)	/* Small Fifo almost full (last chunk is written) */
+#define R592_STATUS_SFIFO_EMPTY		(1 << 21)	/* Small Fifo empty */
+
+							/* Error detection via CRC */
+#define R592_STATUS_SEND_ERR		(1 << 24)	/* Send failed */
+#define R592_STATUS_RECV_ERR		(1 << 25)	/* Recieve failed */
+
+							/* Card state */
+#define R592_STATUS_RDY			(1 << 28)	/* RDY signal recieved */
+#define R592_STATUS_CED			(1 << 29)	/* INT: Command done (serial mode)*/
+#define R592_STATUS_SFIFO_INPUT		(1 << 30)	/* Small fifo recieved data*/
+
+#define R592_SFIFO_SIZE			32		/* total size of small fifo is 32 bytes */
+#define R592_SFIFO_PACKET		8		/* packet size of small fifo */
+
+/* IO control */
+#define R592_IO				0x18
+#define	R592_IO_16			(1 << 16)	/* Set by default, can be cleared */
+#define	R592_IO_18			(1 << 18)	/* Set by default, can be cleared */
+#define	R592_IO_SERIAL1			(1 << 20)	/* Set by default, can be cleared, (cleared on parallel) */
+#define	R592_IO_22			(1 << 22)	/* Set by default, can be cleared */
+#define R592_IO_DIRECTION		(1 << 24)	/* TPC direction (1 write 0 read) */
+#define	R592_IO_26			(1 << 26)	/* Set by default, can be cleared */
+#define	R592_IO_SERIAL2			(1 << 30)	/* Set by default, can be cleared (cleared on parallel), serial doesn't work if unset */
+#define R592_IO_RESET			(1 << 31)	/* Reset, sets defaults*/
+
+
+/* Turns hardware on/off */
+#define R592_POWER			0x20		/* bits 0-7 writeable */
+#define R592_POWER_0			(1 << 0)	/* set on start, cleared on stop - must be set*/
+#define R592_POWER_1			(1 << 1)	/* set on start, cleared on stop - must be set*/
+#define R592_POWER_3			(1 << 3)	/* must be clear */
+#define R592_POWER_20			(1 << 5)	/* set before switch to parallel */
+
+/* IO mode*/
+#define R592_IO_MODE			0x24
+#define R592_IO_MODE_SERIAL		1
+#define R592_IO_MODE_PARALLEL		3
+
+
+/* IRQ,card detection,large fifo (first word irq status, second enable) */
+/* IRQs are ACKed by clearing the bits */
+#define R592_REG_MSC			0x28
+#define R592_REG_MSC_PRSNT		(1 << 1)	/* card present (only status)*/
+#define R592_REG_MSC_IRQ_INSERT		(1 << 8)	/* detect insert / card insered */
+#define R592_REG_MSC_IRQ_REMOVE		(1 << 9)	/* detect removal / card removed */
+#define R592_REG_MSC_FIFO_EMPTY		(1 << 10)	/* fifo is empty */
+#define R592_REG_MSC_FIFO_DMA_DONE	(1 << 11)	/* dma enable / dma done */
+
+#define R592_REG_MSC_FIFO_USER_ORN	(1 << 12)	/* set if software reads empty fifo (if R592_REG_MSC_FIFO_EMPTY is set) */
+#define R592_REG_MSC_FIFO_MISMATH	(1 << 13)	/* set if amount of data in fifo doesn't match amount in TPC */
+#define R592_REG_MSC_FIFO_DMA_ERR	(1 << 14)	/* IO failure */
+#define R592_REG_MSC_LED		(1 << 15)	/* clear to turn led off (only status)*/
+
+#define DMA_IRQ_ACK_MASK \
+	(R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)
+
+#define DMA_IRQ_EN_MASK (DMA_IRQ_ACK_MASK << 16)
+
+#define IRQ_ALL_ACK_MASK 0x00007F00
+#define IRQ_ALL_EN_MASK (IRQ_ALL_ACK_MASK << 16)
+
+/* DMA address for large FIFO read/writes*/
+#define R592_FIFO_DMA			0x2C
+
+/* PIO access to large FIFO (512 bytes) (big endian)*/
+#define R592_FIFO_PIO			0x30
+#define R592_LFIFO_SIZE			512		/* large fifo size */
+
+
+/* large FIFO DMA settings */
+#define R592_FIFO_DMA_SETTINGS		0x34
+#define R592_FIFO_DMA_SETTINGS_EN	(1 << 0)	/* DMA enabled */
+#define R592_FIFO_DMA_SETTINGS_DIR	(1 << 1)	/* Dma direction (1 read, 0 write) */
+#define R592_FIFO_DMA_SETTINGS_CAP	(1 << 24)	/* Dma is aviable */
+
+/* Maybe just an delay */
+/* Bits 17..19 are just number */
+/* bit 16 is set, then bit 20 is waited */
+/* time to wait is about 50 spins * 2 ^ (bits 17..19) */
+/* seems to be possible just to ignore */
+/* Probably debug register */
+#define R592_REG38			0x38
+#define R592_REG38_CHANGE		(1 << 16)	/* Start bit */
+#define R592_REG38_DONE			(1 << 20)	/* HW set this after the delay */
+#define R592_REG38_SHIFT		17
+
+/* Debug register, written (0xABCDEF00) when error happens - not used*/
+#define R592_REG_3C			0x3C
+
+struct r592_device {
+	struct pci_dev *pci_dev;
+	struct memstick_host	*host;		/* host backpointer */
+	struct memstick_request *req;		/* current request */
+
+	/* Registers, IRQ */
+	void __iomem *mmio;
+	int irq;
+	spinlock_t irq_lock;
+	spinlock_t io_thread_lock;
+	struct timer_list detect_timer;
+
+	struct task_struct *io_thread;
+	bool parallel_mode;
+
+	DECLARE_KFIFO(pio_fifo, u8, sizeof(u32));
+
+	/* DMA area */
+	int dma_capable;
+	int dma_error;
+	struct completion dma_done;
+	void *dummy_dma_page;
+	dma_addr_t dummy_dma_page_physical_address;
+
+};
+
+#define DRV_NAME "r592"
+
+
+#define message(format, ...) \
+	printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__)
+
+#define __dbg(level, format, ...) \
+	do { \
+		if (debug >= level) \
+			printk(KERN_DEBUG DRV_NAME \
+				": " format "\n", ## __VA_ARGS__); \
+	} while (0)
+
+
+#define dbg(format, ...)		__dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...)	__dbg(2, format, ## __VA_ARGS__)
+#define dbg_reg(format, ...)		__dbg(3, format, ## __VA_ARGS__)
+
+#endif
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 84+ messages in thread

* Re: [PATCH 0/29] My patch queue for memorystick subsystem
  2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
                   ` (28 preceding siblings ...)
  2010-10-22 23:53 ` [PATCH 29/29] memstick: Add driver for Ricoh R5C592 Card reader Maxim Levitsky
@ 2010-10-25  2:01 ` Maxim Levitsky
  2010-10-25 14:39   ` Alex Dubov
  2010-10-25 16:25   ` Alex Dubov
  29 siblings, 2 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-25  2:01 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Sat, 2010-10-23 at 01:53 +0200, Maxim Levitsky wrote:
> Hi,
> 
> As requested, this is split up series of the work I did for the
> memorystick subsystem.
> 
> All patches compile tested.
> All patches except jmicron patches also run tested on my r592
> The end result of jmicron patches is exactly the same as my old patch
> that did work very well. I will test the patches tommorow though to ensure that
> all of them work for bisectability.
> 
> Please review & merge.
Any update?
Can I expect this in 2.6.37?

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 0/29] My patch queue for memorystick subsystem
  2010-10-25  2:01 ` [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
@ 2010-10-25 14:39   ` Alex Dubov
  2010-10-25 16:07     ` Andrew Morton
  2010-10-25 16:25   ` Alex Dubov
  1 sibling, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 14:39 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML

--- On Sun, 24/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> > 

> Any update?
> Can I expect this in 2.6.37?
> 

If I understand the process correctly, probably no. It's going to take more
time, considering the volume and nature of changes.

There's also additional very unfortunate property of your patchset, namely
you're mixing purely cosmetic and functional patches. Normally, functional
patches should precede the cosmetic one, so that the functionality can be
discussed first.


      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 01/29] memstick: core: header cleanups
  2010-10-22 23:53 ` [PATCH 01/29] memstick: core: header cleanups Maxim Levitsky
@ 2010-10-25 14:44   ` Alex Dubov
  2010-10-26  1:10     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 14:44 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> Received: Friday, 22 October, 2010, 4:53 PM
> * Replace the __attribute__((packed))
> with __packed

This introduces unnecessary noise and can be merged into a common clean-up
patch.

> * Add struct mspro_cmdex_argument, argument for
> MS_TPC_EX_SET_CMD
> * Increase size of inline buffer in memstick_request to 32
> because thats the size of registers and someone might need
> to read them
> all. That structure is allocated one per memstick host, so
> its size
> doesn't matter.

This functional changes are better be joined with the first patch which
actually requires them (these are just 4 lines).

> 
> * Add comments about few members of memstick_request

Belongs to the clean-up or a separate commenting patch.

> 
> Signed-off-by: Maxim Levitsky <maximlevitky@gmail.com>
> ---



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code.
  2010-10-22 23:53 ` [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code Maxim Levitsky
@ 2010-10-25 14:50   ` Alex Dubov
  2010-10-26  1:14     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 14:50 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code.


I'm not sure this purely subjective patch is of any real utility.
And at any rate, it belongs to the end of the patchset (where the clean-up
normally go), not to the beginning.




      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 03/29] memstick: core: add new functions
  2010-10-22 23:53 ` [PATCH 03/29] memstick: core: add new functions Maxim Levitsky
@ 2010-10-25 14:56   ` Alex Dubov
  2010-10-26  1:20     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 14:56 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 03/29] memstick: core: add new functions
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Add a lot of support code that will
> be used later.
> 

You're adding here a lot of temporarily dead code, which, while being
useful, should be better added together with the actual driver
functionality.

Besides this, the patch has a lot of unneeded clean-ups which are better
be set as a separate patch.

And it doesn't conform to the coding guideline either (4 byte indents,
instead of tabs).



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 04/29] memstick: core: rework state machines
  2010-10-22 23:53 ` [PATCH 04/29] memstick: core: rework state machines Maxim Levitsky
@ 2010-10-25 15:01   ` Alex Dubov
  2010-10-26  1:34     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:01 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 04/29] memstick: core: rework state machines
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Make state machines in memstick core
> follow the
> new style.
> 

1. This is an important functional patch. At present, "new style" exists
only in your head. You should make an effort to justify it to everybody
else by providing a rationale in patch description.

2. You are using an integer state variable (instead of function pointers
which were self-describing by virtue of the referred function names).
Please, define an enumerated type for this state variable, giving states
human-readable, descriptive names. If you need to do state variable
arithmetic, you can provide a couple of simple, descriptive macros to
do so:

#define NEXT_STATE(s) (s + 1)

or something along the line.

3. Coding style.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit
  2010-10-22 23:53 ` [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit Maxim Levitsky
@ 2010-10-25 15:07   ` Alex Dubov
  2010-10-26  1:46     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:07 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> This makes it much easier to lookup
> things and reduces size of mspro_block.c

Subjective and irrelevant.
My editor makes it easier to look up things when they are in the same file,
and this declarations are not expected to be used by any other compilation
unit. Belongs to the cosmetic category which should be discussed later.

> Also add debbuging macros so that it becames possible to
> control
> debbuging via module param.
> 

Should be done through a common kernel infrastructure, namely DYNAMIC_DEBUG
feature (pr_debug and friends).



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 06/29] memstick: mspro: kill the BKL
  2010-10-22 23:53 ` [PATCH 06/29] memstick: mspro: kill the BKL Maxim Levitsky
@ 2010-10-25 15:12   ` Alex Dubov
  2010-10-26  1:50     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:12 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 06/29] memstick: mspro: kill the BKL
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> mspro_block_disk_lock already
> protects the code.
> 

It is indeed, but I don't see the functionality this patch is trying to
revert neither in my running kernel (2.6.32.8) nor in current git tree.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 07/29] memstick: mspro: two fixes
  2010-10-22 23:53 ` [PATCH 07/29] memstick: mspro: two fixes Maxim Levitsky
@ 2010-10-25 15:13   ` Alex Dubov
  2010-10-26  1:51     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:13 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 07/29] memstick: mspro: two fixes
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> fix uninitialized spinlock warning on
> resume
> and race in idr_pre_get
> 

I fully agree.

Coding style!



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 08/29] memstick: mspro: add comments to few functions
  2010-10-22 23:53 ` [PATCH 08/29] memstick: mspro: add comments to few functions Maxim Levitsky
@ 2010-10-25 15:18   ` Alex Dubov
  2010-10-26  1:54     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:18 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 08/29] memstick: mspro: add comments to few functions
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> a comment before function is not only
> a good way
> to give some information to the reader, but
> it serves as a good anchor point for diff so that
> it doesn't produce a diff between different
> functions (sigh...)
> 

Comments of new functions belong to the patch which introduces these new
functions. And those functions (as I already said) belong to the patch
which introduces new functionality, using these functions, desirably,
one function at a time.





      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 09/29] memstick: rework state machines + attribute read function
  2010-10-22 23:53 ` [PATCH 09/29] memstick: rework state machines + attribute read function Maxim Levitsky
@ 2010-10-25 15:23   ` Alex Dubov
  2010-10-26  1:57     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:23 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 09/29] memstick: rework state machines + attribute read function
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Code is rewritten to use new style of
> state machines.

As I said before:
1. Rationale for this "new style".
2. Human readable names for states and state transitions.
3. Coding style.


> Attribute read function is cleaned up and commented
> sparsely.
> 

Belongs to separate patch. Attribute read function is quite isolated from
everything else.




      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 10/29] memstick: mspro: create _setup_io helper.
  2010-10-22 23:53 ` [PATCH 10/29] memstick: mspro: create _setup_io helper Maxim Levitsky
@ 2010-10-25 15:25   ` Alex Dubov
  2010-10-26  1:58     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:25 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 10/29] memstick: mspro: create _setup_io helper.
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> This function contains common parts
> of IO setup
> for the state machine, thus reduces the risk
> of using the state machine in wrong way.
> 

1. This should precede the read_attribute function patch.
2. Coding style. 



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD
  2010-10-22 23:53 ` [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD Maxim Levitsky
@ 2010-10-25 15:27   ` Alex Dubov
  2010-10-26  2:00     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:27 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> This little optimization done by Sony
> for
> PRO variant of the cards allows to bundle the param
> register
> with the command and therefore send one TPC less.
> 
> This increases IO throughput somewhat.
> (4.4 -> 4.8 MB/s on Jmicron for example)
> 

1. Names for states.
2. Coding style.
3. Introduction of struct mspro_cmdex_argument belongs to this patch.





      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 12/29] memstick: mspro: rework interface switch
  2010-10-22 23:53 ` [PATCH 12/29] memstick: mspro: rework interface switch Maxim Levitsky
@ 2010-10-25 15:28   ` Alex Dubov
  2010-10-26  2:01     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:28 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 12/29] memstick: mspro: rework interface switch
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Now no old style state machine
> exist.
> Thus this patch removes now unused code.
> 

This patch does somewhat more, than just removing the dead code.
Description/rationale?



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq
  2010-10-22 23:53 ` [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq Maxim Levitsky
@ 2010-10-25 15:41   ` Alex Dubov
  2010-10-26  2:04     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:41 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> This cleans up a lot of code and
> makes the assumption
> (*mrq == &card->current_mrq) official.
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

Unfortunately, the description does not match the patch.
While the main optimization (merging req and card arguments for good) is
fully reasonable given the posterior knowledge of MSPro evolution, this
patch introduces some functional changes as well, which can not be
considered to be a pure cleanup. Some WARN_ONs also appear to be misplaced:

>         if (msb->block_req) {
> -            mspro_block_complete_req(card, (*mrq)->error);
> +            mspro_block_complete_req(card, mrq->error);
>             error = mspro_block_issue_req(card, false);
> 
> -            if (!msb->block_req) {
> +            if (error) {
> +                WARN_ON(msb->block_req);




      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 14/29] memstick: remove the memstick_set_rw_addr
  2010-10-22 23:53 ` [PATCH 14/29] memstick: remove the memstick_set_rw_addr Maxim Levitsky
@ 2010-10-25 15:55   ` Alex Dubov
  2010-10-26  2:08     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:55 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 14/29] memstick: remove the memstick_set_rw_addr
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Remove this function, what was
> last user that did send the MS_TPC_SET_RW_REG_ADRS
> directly.
> 
> Just invalidate the register window, and next register
> read/write will send that tpc automaticly.
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

How is an obscure invalidate_reg_window function is any better than
explicit set_rw_addr? Total number of calls to either of them is exactly
the same.

Sony state machine diagrams suggest that doing a precise set_rw_addr when
necessary is a good thing. The feature was originally conceived because
Sony intended to manufacture MSIO and hybrid devices, which might have very
large number of registers (hundreds). It was also supposed to help with
backward compatibility of devices, as well as with DRM functionality

We know, at this point of time, that Sony is sort of loosing the format
war, so MSIO devices these days are very hard to come by. However, some
hybrid (Transfer Jet) and DRM-secured devices still exist and it is wise
to retain functionality which can help to operate those (I don't have full
details on their operation, but it doesn't mean we should forget them
outright).



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 15/29] memstick: jmb38x_ms: Create header
  2010-10-22 23:53 ` [PATCH 15/29] memstick: jmb38x_ms: Create header Maxim Levitsky
@ 2010-10-25 15:56   ` Alex Dubov
  2010-10-26  2:10     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:56 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 15/29] memstick: jmb38x_ms: Create header
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> In the new header add:
> 
> * debug macros
> * Registers + some documntation
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

Yet again, what's wrong with DYNAMIC_DEBUG?



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g
  2010-10-22 23:53 ` [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g Maxim Levitsky
@ 2010-10-25 15:58   ` Alex Dubov
  2010-10-26  2:13     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 15:58 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> This just makes it easier to type
> function names
> while still keeping the meaning
> Driver name and filenames are left unchanged.
> 
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

What sort of patch/argument is this?
Function prefix should match the module name, to be immediately and
unambiguously identifiable in the stack trace.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together.
  2010-10-22 23:53 ` [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together Maxim Levitsky
@ 2010-10-25 16:00   ` Alex Dubov
  2010-10-26  2:14     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:00 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together.
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> No functional changes, just group
> these funtions together.
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

As before, patch with dubious utility.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 18/29] memstick: jmb38x_ms: rename functions
  2010-10-22 23:53 ` [PATCH 18/29] memstick: jmb38x_ms: rename functions Maxim Levitsky
@ 2010-10-25 16:00   ` Alex Dubov
  2010-10-26  2:17     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:00 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 18/29] memstick: jmb38x_ms: rename functions
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Give functions names that I hope will
> describe them better.
> Its a matter of personal taste somewhat, I admit.
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

Just like 2/3 of your patches in this pack, until now.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions
  2010-10-22 23:53 ` [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions Maxim Levitsky
@ 2010-10-25 16:03   ` Alex Dubov
  2010-10-26  2:19     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:03 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> All over the code it is a bit easier
> to see the
> register access with this patch. Also set/clear mask
> helpers refactor code a bit, but the biggest reason
> for this patch is to make it possible to trace register
> read/writes with a flip of a module param.
> 
> Currently these functions are unused, but will be by later
> code
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>

This looks like a case of:
1. You've run into a technical difficulty.
2. You used some temporary code to resolve and document it.
3. Now this temporary code is forever here to stay.




      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 20/29] memstick: jmb38x_ms: rework PIO
  2010-10-22 23:53 ` [PATCH 20/29] memstick: jmb38x_ms: rework PIO Maxim Levitsky
@ 2010-10-25 16:05   ` Alex Dubov
  2010-10-26  2:21     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:05 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 20/29] memstick: jmb38x_ms: rework PIO
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Rewrite PIO code to be just simplier
> and shorter,
> and comment not so obivous parts.
> 
> Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
> ---

Yet, you are fixing something that was not broken before.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 0/29] My patch queue for memorystick subsystem
  2010-10-25 14:39   ` Alex Dubov
@ 2010-10-25 16:07     ` Andrew Morton
  2010-10-25 16:10       ` Alex Dubov
  2010-10-26  2:32       ` Maxim Levitsky
  0 siblings, 2 replies; 84+ messages in thread
From: Andrew Morton @ 2010-10-25 16:07 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Maxim Levitsky, LKML

On Mon, 25 Oct 2010 07:39:58 -0700 (PDT) Alex Dubov <oakad@yahoo.com> wrote:

> Normally, functional
> patches should precede the cosmetic one, so that the functionality can be
> discussed first.

More usually it's the other way around, actually: cleanups come first.

Because the cleanups are usually uncontroversial, and because
substantive changes against cleaner code are easier to
review/understand and because the substantive changes are then easier
to revert or fix.

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution
  2010-10-22 23:53 ` [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution Maxim Levitsky
@ 2010-10-25 16:08   ` Alex Dubov
  2010-10-26  2:22     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:08 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Code rewritten to make it simplier.
> A lot of debug output is added to help
> diagnose bugs.
> 
> No major functional changes
> 
> Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>

Was not broken beforehand.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 0/29] My patch queue for memorystick subsystem
  2010-10-25 16:07     ` Andrew Morton
@ 2010-10-25 16:10       ` Alex Dubov
  2010-10-26  2:32       ` Maxim Levitsky
  1 sibling, 0 replies; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:10 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Maxim Levitsky, LKML

> 
> > Normally, functional
> > patches should precede the cosmetic one, so that the
> functionality can be
> > discussed first.
> 
> More usually it's the other way around, actually: cleanups
> come first.
> 
> Because the cleanups are usually uncontroversial, and
> because
> substantive changes against cleaner code are easier to
> review/understand and because the substantive changes are
> then easier
> to revert or fix.
> 


My problem here is that out of 30 patches, 20 appear to be rewrites and
clean-ups of things not broken.

That's why I'd rather prefer to see actual functional changes first.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 22/29] memstick: jmb38x_ms: rework ISR
  2010-10-22 23:53 ` [PATCH 22/29] memstick: jmb38x_ms: rework ISR Maxim Levitsky
@ 2010-10-25 16:11   ` Alex Dubov
  2010-10-26  2:23     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:11 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 22/29] memstick: jmb38x_ms: rework ISR
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> New ISR is simplier.
> Also it only services the hardware when we expect to
> thus it workarounds the stuck write ready bit hw bug.
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

Probably it is.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default
  2010-10-22 23:53 ` [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default Maxim Levitsky
@ 2010-10-25 16:12   ` Alex Dubov
  2010-10-26  2:29     ` Maxim Levitsky
  0 siblings, 1 reply; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:12 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky

--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> This is to workaround a wierd
> hardware bug:
> 
> If PIO write is used, and then after it DMA write is used,
> DMA
> engine stops doing writes.
> That condition even persists after device reset.
> 
> To be maxumum safe, we do dma to a scratch page
> and memcpy from/to it.
> 
> Besides this change should just improve performance.
> 
> Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> ---

I have not noticed this one before, and for all I know the driver was
tested at Jmicron.
Can you explain the issue a bit more?



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another.
  2010-10-22 23:53 ` [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another Maxim Levitsky
@ 2010-10-25 16:14   ` Alex Dubov
  0 siblings, 0 replies; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:14 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another.
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>, "Maxim Levitsky" <maxim-levitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Lift some common code.
> Also make sure new TPC is always exacuted from a tasklet.
> While this decreases IO speed a bit, this makes sure
> we won't have large latency.
> 
> Signed-off-by: Maxim Levitsky <maxim-levitsky@gmail.com>
> ---

Probably a good idea.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset
  2010-10-22 23:53 ` [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset Maxim Levitsky
@ 2010-10-25 16:17   ` Alex Dubov
  0 siblings, 0 replies; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:17 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML, Maxim Levitsky



--- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:

> From: Maxim Levitsky <maximlevitsky@gmail.com>
> Subject: [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset
> To: "Alex Dubov" <oakad@yahoo.com>
> Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> Received: Friday, 22 October, 2010, 4:53 PM
> Move the code into functions.
> Reset clock on init - fixes serial mode
> 
> Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
> ---

Ok.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 0/29] My patch queue for memorystick subsystem
  2010-10-25  2:01 ` [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
  2010-10-25 14:39   ` Alex Dubov
@ 2010-10-25 16:25   ` Alex Dubov
  1 sibling, 0 replies; 84+ messages in thread
From: Alex Dubov @ 2010-10-25 16:25 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: Andrew Morton, LKML

I would like to summarize my impression until now:

1. There are 3 functional fixes to Jmicron driver, which are rather small
when taken to their essence (disregarding renames and idle code movements).

2. There is 1 functional enhancement to the MS Pro driver, not too big,
pertaining to extended command execution and resulting in 10% speedup in
some cases.

3. There are 25 patches which just rewrite everything for no good reason
(by this I mean bugs or missing functionality).

Why don't we deal with p.1 and p.2 first, before going to the p.3, as I
suggested from the beginning?

I don't have any specific objections to Ricoh driver as it is.



      

^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 01/29] memstick: core: header cleanups
  2010-10-25 14:44   ` Alex Dubov
@ 2010-10-26  1:10     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:10 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML, Maxim Levitsky

On Mon, 2010-10-25 at 07:44 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > Received: Friday, 22 October, 2010, 4:53 PM
> > * Replace the __attribute__((packed))
> > with __packed
> 
> This introduces unnecessary noise and can be merged into a common clean-up
> patch.
And what value will that add?

> 
> > * Add struct mspro_cmdex_argument, argument for
> > MS_TPC_EX_SET_CMD
> > * Increase size of inline buffer in memstick_request to 32
> > because thats the size of registers and someone might need
> > to read them
> > all. That structure is allocated one per memstick host, so
> > its size
> > doesn't matter.
> 
> This functional changes are better be joined with the first patch which
> actually requires them (these are just 4 lines).
Not fully against that, but then what value will that add too?
Currently memstick.h host many unused structures for MS IO stuff.
And for god's sake it has MS_TPC_EX_SET_CMD declared,
so I just add the structure for its argument, whats wrong with doing
that here?

> 
> > 
> > * Add comments about few members of memstick_request
> 
> Belongs to the clean-up or a separate commenting patch.
Why?

As long as the patch is crearly readable I don't see a reason to add
more patches.


Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code.
  2010-10-25 14:50   ` Alex Dubov
@ 2010-10-26  1:14     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:14 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 07:50 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code.
> 
> 
> I'm not sure this purely subjective patch is of any real utility.
> And at any rate, it belongs to the end of the patchset (where the clean-up
> normally go), not to the beginning.

Could somebody else comment on this?
I mean memstick.c/h contains two types of functions.
One is useful only for low level drivers, and other only for high level
drivers. Whats wrong with at least grouping that together?
It probably even better to put them to separate files...

As for doing that late, I exaplained that once in reply to Morton.
It was much easier to split patches this way, and really doesn't matter
otherwise.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 03/29] memstick: core: add new functions
  2010-10-25 14:56   ` Alex Dubov
@ 2010-10-26  1:20     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:20 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 07:56 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 03/29] memstick: core: add new functions
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Add a lot of support code that will
> > be used later.
> > 
> 
> You're adding here a lot of temporarily dead code, which, while being
> useful, should be better added together with the actual driver
> functionality.
So what?
What is wrong with that?
Why should I mix things together?


> 
> Besides this, the patch has a lot of unneeded clean-ups which are better
> be set as a separate patch.
What cleanups?
So I added the memstick_power_off and make code use it
If you want even that as separate patch, ok.

And memstick_invalidate_reg_window in memstick_power_on?
Again at any rate it will be invalid there.
(Maybe I should have put that in memstick_power_off actually, will do)

If you want me to put these changes in separate patches, ok, I do it.


> 
> And it doesn't conform to the coding guideline either (4 byte indents,
> instead of tab
What?
I checked the patch with checkpatch.pl. It didn't complain.
I also use 8 byte tabs not 4.
Will look at that, thanks.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 04/29] memstick: core: rework state machines
  2010-10-25 15:01   ` Alex Dubov
@ 2010-10-26  1:34     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:34 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:01 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 04/29] memstick: core: rework state machines
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Make state machines in memstick core
> > follow the
> > new style.
> > 
> 
> 1. This is an important functional patch. At present, "new style" exists
> only in your head. You should make an effort to justify it to everybody
> else by providing a rationale in patch description.
I already explained that.
Ok. I add that explanation to patch header.


> 
> 2. You are using an integer state variable (instead of function pointers
> which were self-describing by virtue of the referred function names).
> Please, define an enumerated type for this state variable, giving states
> human-readable, descriptive names. If you need to do state variable
> arithmetic, you can provide a couple of simple, descriptive macros to
> do so:
> 
> #define NEXT_STATE(s) (s + 1)
Do we have a corporate policy of no magic numbers?
Like this: http://thedailywtf.com/Articles/Avoiding-Magic-Constants.aspx


The issue here (I explained it already) is that I often use card-state
++; to get to next state;
Other the enforcing the policy the suggested #define it won't help.

card->state++ allows me for example to fallback through switch states
and go by default to next state by default without additional code.
If I bury state numbers with #defines or enums, the assumptions that
states appear in switch in ascending order won't be obvious anymore
and nether that adding 1 to state will bring me to next switch case.





> 
> or something along the line.
> 
> 3. Coding style.
Passed checkpatch.pl. Could you show me the lines affected?


Best regards,
	Maxim Levitsky



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit
  2010-10-25 15:07   ` Alex Dubov
@ 2010-10-26  1:46     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:46 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:07 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > This makes it much easier to lookup
> > things and reduces size of mspro_block.c
> 
> Subjective and irrelevant.
> My editor makes it easier to look up things when they are in the same file,
> and this declarations are not expected to be used by any other compilation
> unit. Belongs to the cosmetic category which should be discussed later.
I agree that it is subjective.
However when you have 2 files, you can always open them in different
copies of an editor, terminal tabs.
When you have decorations in one file you depend on the editor a lot.
also its not about finding them.
Its about distrupting the workflow, because once you find the
declaration you need to find the place you were before.
I understand that some editors help with that, yea.


> 
> > Also add debbuging macros so that it becames possible to
> > control
> > debbuging via module param.
> > 
> 
> Should be done through a common kernel infrastructure, namely DYNAMIC_DEBUG
> feature (pr_debug and friends).
How a user can turn DYNAMIC_DEBUG on?
How about different levels of verbosity?
Last time I checked DYNAMIC_DEBUG doesn't allow that.
Besides the macros I add revert to 
DYNAMIC_DEBUG if user doesn't specify the debug= module param.

When dynamic debugs grows that features (I have seen a ddebug= patchset,
hope it gets merged, I will just trim down these macros).
Besides the goal of these macros is to reduce typing.
I need to add/remove the debug printouts very often, and then I don't
want even to type that '\n' at the end.
Besides, a lot of drivers are doing that. Just look around.

I already added similiar looking macros to 2 my other driver
 (r852 sm_ftls and ene_cir) and no complains.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 06/29] memstick: mspro: kill the BKL
  2010-10-25 15:12   ` Alex Dubov
@ 2010-10-26  1:50     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:50 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:12 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 06/29] memstick: mspro: kill the BKL
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > mspro_block_disk_lock already
> > protects the code.
> > 
> 
> It is indeed, but I don't see the functionality this patch is trying to
> revert neither in my running kernel (2.6.32.8) nor in current git tree.

This patch is against 2.6.35 which moved BKL from core to drivers so
that maintainers could take action.
Actually due to lack of action from memstick maintainers, this patch
doesn't apply to mainline as now BKL is replaced with yet another
unnecessary mutex.
I have a patch to remove it.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 07/29] memstick: mspro: two fixes
  2010-10-25 15:13   ` Alex Dubov
@ 2010-10-26  1:51     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:51 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:13 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 07/29] memstick: mspro: two fixes
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > fix uninitialized spinlock warning on
> > resume
> > and race in idr_pre_get
> > 
> 
> I fully agree.
> 
> Coding style!
Passed checkpatch.pl.

-- 
Best regards,
        Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 08/29] memstick: mspro: add comments to few functions
  2010-10-25 15:18   ` Alex Dubov
@ 2010-10-26  1:54     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:54 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:18 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 08/29] memstick: mspro: add comments to few functions
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > a comment before function is not only
> > a good way
> > to give some information to the reader, but
> > it serves as a good anchor point for diff so that
> > it doesn't produce a diff between different
> > functions (sigh...)
> > 
> 
> Comments of new functions belong to the patch which introduces these new
> functions. And those functions (as I already said) belong to the patch
> which introduces new functionality, using these functions, desirably,
> one function at a time.
You did read the patch didn't you?
I added few comments to _existing_ functions something that code really
needs.
I also did explain why did I do that here, didn't I?
It makes next patch cleaner, as diff doesn't attempt to create a diff
between different functions.


-- 
Best regards,
        Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 09/29] memstick: rework state machines + attribute read function
  2010-10-25 15:23   ` Alex Dubov
@ 2010-10-26  1:57     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:57 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:23 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 09/29] memstick: rework state machines + attribute read function
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Code is rewritten to use new style of
> > state machines.
> 
> As I said before:
> 1. Rationale for this "new style".
OK, will explain in patch description better.


> 2. Human readable names for states and state transitions.
Don't want to do, I explained why.


> 3. Coding style.
passed checkpatch.pl



> 
> 
> > Attribute read function is cleaned up and commented
> > sparsely.
> > 
> 
> Belongs to separate patch. Attribute read function is quite isolated from
> everything else.
Its not.
Your old attribute read function plays games with param register,
so I will need to change it first to use global param register, and then
port it. I hate doing that. If you insist, ok.



-- 
Best regards,
        Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 10/29] memstick: mspro: create _setup_io helper.
  2010-10-25 15:25   ` Alex Dubov
@ 2010-10-26  1:58     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  1:58 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:25 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 10/29] memstick: mspro: create _setup_io helper.
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > This function contains common parts
> > of IO setup
> > for the state machine, thus reduces the risk
> > of using the state machine in wrong way.
> > 
> 
> 1. This should precede the read_attribute function patch.
Why?

> 2. Coding style. 
checkpatch.pl passed.


-- 
Best regards,
        Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD
  2010-10-25 15:27   ` Alex Dubov
@ 2010-10-26  2:00     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:00 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:27 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > This little optimization done by Sony
> > for
> > PRO variant of the cards allows to bundle the param
> > register
> > with the command and therefore send one TPC less.
> > 
> > This increases IO throughput somewhat.
> > (4.4 -> 4.8 MB/s on Jmicron for example)
> > 
> 
> 1. Names for states.
> 2. Coding style.
Already said that many times.
It passes checkpatch.pl. 


> 3. Introduction of struct mspro_cmdex_argument belongs to this patch.
I won't fight over that one, but I think that its doesn't matter.


Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 12/29] memstick: mspro: rework interface switch
  2010-10-25 15:28   ` Alex Dubov
@ 2010-10-26  2:01     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:01 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:28 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 12/29] memstick: mspro: rework interface switch
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Now no old style state machine
> > exist.
> > Thus this patch removes now unused code.
> > 
> 
> This patch does somewhat more, than just removing the dead code.
> Description/rationale?

I will update the patch description.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq
  2010-10-25 15:41   ` Alex Dubov
@ 2010-10-26  2:04     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:04 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:41 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > This cleans up a lot of code and
> > makes the assumption
> > (*mrq == &card->current_mrq) official.
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> Unfortunately, the description does not match the patch.
> While the main optimization (merging req and card arguments for good) is
> fully reasonable given the posterior knowledge of MSPro evolution, this
> patch introduces some functional changes as well, which can not be
> considered to be a pure cleanup. 
Agreed, some stuff slipped to that patch, will split.



> Some WARN_ONs also appear to be misplaced:
> 
> >         if (msb->block_req) {
> > -            mspro_block_complete_req(card, (*mrq)->error);
> > +            mspro_block_complete_req(card, mrq->error);
> >             error = mspro_block_issue_req(card, false);
> > 
> > -            if (!msb->block_req) {
> > +            if (error) {
> > +                WARN_ON(msb->block_req);
Nope that on purpose.
If mspro_block_issue_req returns error, the msb->block_req must be NULL.
 

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 14/29] memstick: remove the memstick_set_rw_addr
  2010-10-25 15:55   ` Alex Dubov
@ 2010-10-26  2:08     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:08 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:55 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 14/29] memstick: remove the memstick_set_rw_addr
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Remove this function, what was
> > last user that did send the MS_TPC_SET_RW_REG_ADRS
> > directly.
> > 
> > Just invalidate the register window, and next register
> > read/write will send that tpc automaticly.
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> How is an obscure invalidate_reg_window function is any better than
> explicit set_rw_addr? Total number of calls to either of them is exactly
> the same.
Nope.
I just set the reg window where it should be: in register read/write
functions.
Here we tampered with register window by using another card structure,
so we invalidate it. Simple.
The point is that I send the register window update just before register
read/write, and optionaly skip that if cached version matches the one I
need.


> 
> Sony state machine diagrams suggest that doing a precise set_rw_addr when
> necessary is a good thing. 
And that exactly what I am doing.
I am setting that window just before a register read/write.


> The feature was originally conceived because
> Sony intended to manufacture MSIO and hybrid devices, which might have very
> large number of registers (hundreds). It was also supposed to help with
> backward compatibility of devices, as well as with DRM functionality
> 
> We know, at this point of time, that Sony is sort of loosing the format
> war, so MSIO devices these days are very hard to come by. However, some
> hybrid (Transfer Jet) and DRM-secured devices still exist and it is wise
> to retain functionality which can help to operate those (I don't have full
> details on their operation, but it doesn't mean we should forget them
> outright).


Best regards,
	Maxim Levitsky



^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 15/29] memstick: jmb38x_ms: Create header
  2010-10-25 15:56   ` Alex Dubov
@ 2010-10-26  2:10     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:10 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:56 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 15/29] memstick: jmb38x_ms: Create header
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > In the new header add:
> > 
> > * debug macros
> > * Registers + some documntation
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> Yet again, what's wrong with DYNAMIC_DEBUG?

DYNAMIC_DEBUG:

a) has to be enabled by distro.
b) lacks debug levels.

And it is used unless user sets the debug= argument.
You did read the patch didn't you?


Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g
  2010-10-25 15:58   ` Alex Dubov
@ 2010-10-26  2:13     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:13 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 08:58 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > This just makes it easier to type
> > function names
> > while still keeping the meaning
> > Driver name and filenames are left unchanged.
> > 
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> What sort of patch/argument is this?
> Function prefix should match the module name, to be immediately and
> unambiguously identifiable in the stack trace.
In that case maybe rename the module too?
'jmb38x_ms' is just a mouthful as Andrew Morton would say.

I mean if you really really dislike that, I could revert it, but for
peoples sake, whats wrong with that?

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together.
  2010-10-25 16:00   ` Alex Dubov
@ 2010-10-26  2:14     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:14 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 09:00 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together.
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > No functional changes, just group
> > these funtions together.
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> As before, patch with dubious utility.
But no harm ether, no?

Just makes code a bit easier to read.
Again that patch was done to minimize diff w/original when I was
splitting patches.
If you really are againt it, I can revert that.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 18/29] memstick: jmb38x_ms: rename functions
  2010-10-25 16:00   ` Alex Dubov
@ 2010-10-26  2:17     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:17 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 09:00 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 18/29] memstick: jmb38x_ms: rename functions
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Give functions names that I hope will
> > describe them better.
> > Its a matter of personal taste somewhat, I admit.
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> Just like 2/3 of your patches in this pack, until now.
And about 90% of patches that go to kernel no?

Besides again, that was done to minimize diff, and I made _pio postfixes
to make clear that functions are used for PIO.



Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions
  2010-10-25 16:03   ` Alex Dubov
@ 2010-10-26  2:19     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:19 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 09:03 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > All over the code it is a bit easier
> > to see the
> > register access with this patch. Also set/clear mask
> > helpers refactor code a bit, but the biggest reason
> > for this patch is to make it possible to trace register
> > read/writes with a flip of a module param.
> > 
> > Currently these functions are unused, but will be by later
> > code
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> 
> This looks like a case of:
> 1. You've run into a technical difficulty.
> 2. You used some temporary code to resolve and document it.
> 3. Now this temporary code is forever here to stay.
What? What you are accusing me of?
This is just an insult.

Having a simple way to trace register writes is always a good thing.

Also I have very similar code in ene_ir and r852. No complains.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 20/29] memstick: jmb38x_ms: rework PIO
  2010-10-25 16:05   ` Alex Dubov
@ 2010-10-26  2:21     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:21 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 09:05 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 20/29] memstick: jmb38x_ms: rework PIO
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Rewrite PIO code to be just simplier
> > and shorter,
> > and comment not so obivous parts.
> > 
> > Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
> > ---
> 
> Yet, you are fixing something that was not broken before.

A code that is hard to read is broken even if it works, because its very
easy for anyone to break it accidentally.
Anybody disagree (except you)?

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution
  2010-10-25 16:08   ` Alex Dubov
@ 2010-10-26  2:22     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:22 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 09:08 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > Code rewritten to make it simplier.
> > A lot of debug output is added to help
> > diagnose bugs.
> > 
> > No major functional changes
> > 
> > Signed-off-by: Maxim Levitsky<maximlevitsky@gmail.com>
> 
> Was not broken beforehand.

Yet is was.
Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 22/29] memstick: jmb38x_ms: rework ISR
  2010-10-25 16:11   ` Alex Dubov
@ 2010-10-26  2:23     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:23 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 09:11 -0700, Alex Dubov wrote:
> 
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 22/29] memstick: jmb38x_ms: rework ISR
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > New ISR is simplier.
> > Also it only services the hardware when we expect to
> > thus it workarounds the stuck write ready bit hw bug.
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> Probably it is.
I am very happy to see you agree at least on this one.

Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default
  2010-10-25 16:12   ` Alex Dubov
@ 2010-10-26  2:29     ` Maxim Levitsky
  0 siblings, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:29 UTC (permalink / raw)
  To: Alex Dubov; +Cc: Andrew Morton, LKML

On Mon, 2010-10-25 at 09:12 -0700, Alex Dubov wrote:
> --- On Fri, 22/10/10, Maxim Levitsky <maximlevitsky@gmail.com> wrote:
> 
> > From: Maxim Levitsky <maximlevitsky@gmail.com>
> > Subject: [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default
> > To: "Alex Dubov" <oakad@yahoo.com>
> > Cc: "Andrew Morton" <akpm@linux-foundation.org>, "LKML" <linux-kernel@vger.kernel.org>, "Maxim Levitsky" <maximlevitsky@gmail.com>
> > Received: Friday, 22 October, 2010, 4:53 PM
> > This is to workaround a wierd
> > hardware bug:
> > 
> > If PIO write is used, and then after it DMA write is used,
> > DMA
> > engine stops doing writes.
> > That condition even persists after device reset.
> > 
> > To be maxumum safe, we do dma to a scratch page
> > and memcpy from/to it.
> > 
> > Besides this change should just improve performance.
> > 
> > Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
> > ---
> 
> I have not noticed this one before, and for all I know the driver was
> tested at Jmicron.
> Can you explain the issue a bit more?
Because you didn't test MS standard, or always wrote OOB and param by
seperate TPCs.

You really don't read my mail.

<quote>
***Appendix***

Jmicron hardware bugs (the novel):

#1: FIFO write ready bit in INT status register is stuck to 1.
   It is stuck forever as soon as fifo
   is used for writing even once.
   Therefore if interrupt is shared (and here it is), its easy
   to 'service' the device while it doesn't need any service


#2: Its not possible to stuff the FIFO before TPC transfer.
   One really have to wait for write ready interrupt, even though the
write ready status is stuck.


#3: TPCs with non 4 aligned length woes:
   Facts:

   * non 4 aligned DMA write hangs the system hard, maybe on bus level.

   * PIO read succedes but controller truncates the data stored in the
FIFO to closest 4 byte boundary.
   That is if you read 26 bytes, it will save 24 bytes in the FIFO

   * TPC_P0, TPC_P1 not aligned transfters work just fine despite a
statement in the datasheet
   (only mention of this problem)


#4: As soon as write PIO is used, then later write DMA fails.
   Facts:

   * This is triggered only by PIO write of registers
   (only happens in ms_block.c when it writes param + oob. Thats why
mspro_blk isn't affected)
   Doing short DMA writes is a nice workaround.

   * Doing PIO writes in h_msb_read_page don't cause the problem.
     Therefore the bug causing sequence should be similiar to
h_msb_write_block:

       1. PIO write of param + extra (10 bytes) or even padded to 12 or
16 bytes
       2. inline write (TPC_P0) of MS_CMD_BLOCK_WRITE + wait for int
       3. read of INT register via STATUS
       3. DMA write of MS_TPC_WRITE_LONG_DATA
       4. DMA write of MS_TPC_WRITE_LONG_DATA
           ---------timeout-----------
 
   * In fact first DMA write succedes, but next one fails, and so do all
following writes

   * The problem persits till reboot, and shows up even if PIO isn't
used again.
   Other way to "fix" it, is to put device in D3 and back to D0

   * Serial/parallel mode don't affect anything.

   After bug reproduction:

    * DMA writes stop working completely, therefore mspro_blk looses
writes as well

    * PIO still works just fine. Its possible just to load the driver
without dma support, and it works correctly.

    * DMA reads work just fine.

#5: Auto_Get_INT feature just doesn't work.
   Datasheet says that intreg is placed to TPC_P0, but that doesn't
happen....
</quote>


^ permalink raw reply	[flat|nested] 84+ messages in thread

* Re: [PATCH 0/29] My patch queue for memorystick subsystem
  2010-10-25 16:07     ` Andrew Morton
  2010-10-25 16:10       ` Alex Dubov
@ 2010-10-26  2:32       ` Maxim Levitsky
  1 sibling, 0 replies; 84+ messages in thread
From: Maxim Levitsky @ 2010-10-26  2:32 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Alex Dubov, LKML

On Mon, 2010-10-25 at 09:07 -0700, Andrew Morton wrote:
> On Mon, 25 Oct 2010 07:39:58 -0700 (PDT) Alex Dubov <oakad@yahoo.com> wrote:
> 
> > Normally, functional
> > patches should precede the cosmetic one, so that the functionality can be
> > discussed first.
> 
> More usually it's the other way around, actually: cleanups come first.
> 
> Because the cleanups are usually uncontroversial, and because
> substantive changes against cleaner code are easier to
> review/understand and because the substantive changes are then easier
> to revert or fix.

Exactly.

Now let me explain another technical reason why I did it that way.
First I created one big patch per driver I changed.
It really wasn't reviewable, but it was intended to review the end
result (the source file after patch was applied).
I did that because its really slows you down when you try to edit at
same time many patches. You have endless conflicts, you do lot of work
that you just remove in next patch etc.
Anyway this patchseries is a result of a lot of hard work (about month).



Alex pointer me that that isn't acceptable in linux community.
OK. I decided to bite the bullet and do that. It took me 2 full days to
split patches, test them (after all, I do honor the rule of
bisesctability).

Now why I put the cosmetic patches first?

Because that reduces conflicts during patch splitting dramaticly.

Consider this stack:


3: <top>
2: <few functions moved>
1: <few functions rewritten>
0: <existing source>

If I want to change patch #1, I will have to redo the patch #2 from the
start. That really sucks.


Now I could skip the functions that move code around, rename functions
etc to make Alex happy, but my goal was to minimize differences between
split-up series and original patch, so I could spare hard debugging.

This is result of lot of hard work.
I really want to see that in 2.6.37.


Best regards,
	Maxim Levitsky


^ permalink raw reply	[flat|nested] 84+ messages in thread

end of thread, other threads:[~2010-10-26  2:32 UTC | newest]

Thread overview: 84+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-22 23:53 [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
2010-10-22 23:53 ` [PATCH 01/29] memstick: core: header cleanups Maxim Levitsky
2010-10-25 14:44   ` Alex Dubov
2010-10-26  1:10     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 02/29] memstick: core: reorder functions This patch just reorders functions in memstick.c So that host specific and card driver specific functions are now grouped together. This makes it easier to understand the code Maxim Levitsky
2010-10-25 14:50   ` Alex Dubov
2010-10-26  1:14     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 03/29] memstick: core: add new functions Maxim Levitsky
2010-10-25 14:56   ` Alex Dubov
2010-10-26  1:20     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 04/29] memstick: core: rework state machines Maxim Levitsky
2010-10-25 15:01   ` Alex Dubov
2010-10-26  1:34     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 05/29] memstick: mspro_block: move declarations to header and refactor things a bit Maxim Levitsky
2010-10-25 15:07   ` Alex Dubov
2010-10-26  1:46     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 06/29] memstick: mspro: kill the BKL Maxim Levitsky
2010-10-25 15:12   ` Alex Dubov
2010-10-26  1:50     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 07/29] memstick: mspro: two fixes Maxim Levitsky
2010-10-25 15:13   ` Alex Dubov
2010-10-26  1:51     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 08/29] memstick: mspro: add comments to few functions Maxim Levitsky
2010-10-25 15:18   ` Alex Dubov
2010-10-26  1:54     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 09/29] memstick: rework state machines + attribute read function Maxim Levitsky
2010-10-25 15:23   ` Alex Dubov
2010-10-26  1:57     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 10/29] memstick: mspro: create _setup_io helper Maxim Levitsky
2010-10-25 15:25   ` Alex Dubov
2010-10-26  1:58     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 11/29] memstick: mspro: use MS_TPC_EX_SET_CMD Maxim Levitsky
2010-10-25 15:27   ` Alex Dubov
2010-10-26  2:00     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 12/29] memstick: mspro: rework interface switch Maxim Levitsky
2010-10-25 15:28   ` Alex Dubov
2010-10-26  2:01     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 13/29] memstick: core: stop passing pointer to card->current_mrq Maxim Levitsky
2010-10-25 15:41   ` Alex Dubov
2010-10-26  2:04     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 14/29] memstick: remove the memstick_set_rw_addr Maxim Levitsky
2010-10-25 15:55   ` Alex Dubov
2010-10-26  2:08     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 15/29] memstick: jmb38x_ms: Create header Maxim Levitsky
2010-10-25 15:56   ` Alex Dubov
2010-10-26  2:10     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 16/29] memstick: jmb38x_ms: s/jmb38x_ms/j38ms/g Maxim Levitsky
2010-10-25 15:58   ` Alex Dubov
2010-10-26  2:13     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 17/29] memstick: jmb38x_ms: move "reg_data" functions together Maxim Levitsky
2010-10-25 16:00   ` Alex Dubov
2010-10-26  2:14     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 18/29] memstick: jmb38x_ms: rename functions Maxim Levitsky
2010-10-25 16:00   ` Alex Dubov
2010-10-26  2:17     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 19/29] memstick: jmb38x_ms: add register read/write functions Maxim Levitsky
2010-10-25 16:03   ` Alex Dubov
2010-10-26  2:19     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 20/29] memstick: jmb38x_ms: rework PIO Maxim Levitsky
2010-10-25 16:05   ` Alex Dubov
2010-10-26  2:21     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 21/29] memstick: jmb38x_ms: rework TPC execution Maxim Levitsky
2010-10-25 16:08   ` Alex Dubov
2010-10-26  2:22     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 22/29] memstick: jmb38x_ms: rework ISR Maxim Levitsky
2010-10-25 16:11   ` Alex Dubov
2010-10-26  2:23     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 23/29] memstick: jmb38x_ms: use DMA for all TPCs with len greater that 8 by default Maxim Levitsky
2010-10-25 16:12   ` Alex Dubov
2010-10-26  2:29     ` Maxim Levitsky
2010-10-22 23:53 ` [PATCH 24/29] memstick: jmb38x_ms: rework processing of the TPC one after another Maxim Levitsky
2010-10-25 16:14   ` Alex Dubov
2010-10-22 23:53 ` [PATCH 25/29] memstick: jmb38x_ms: pass j38ms_host to few functions instead of memstick_host Maxim Levitsky
2010-10-22 23:53 ` [PATCH 26/29] memstick: jmb38x_ms: rework hardware setup/reset Maxim Levitsky
2010-10-25 16:17   ` Alex Dubov
2010-10-22 23:53 ` [PATCH 27/29] memstick: jmb38x_ms: minor additions Maxim Levitsky
2010-10-22 23:53 ` [PATCH 28/29] memstick: add support for legacy memorysticks Maxim Levitsky
2010-10-22 23:53 ` [PATCH 29/29] memstick: Add driver for Ricoh R5C592 Card reader Maxim Levitsky
2010-10-25  2:01 ` [PATCH 0/29] My patch queue for memorystick subsystem Maxim Levitsky
2010-10-25 14:39   ` Alex Dubov
2010-10-25 16:07     ` Andrew Morton
2010-10-25 16:10       ` Alex Dubov
2010-10-26  2:32       ` Maxim Levitsky
2010-10-25 16:25   ` Alex Dubov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.