[PATCH v6 2/3] mtd: spi-nor: Add spi-nor flash device synchronization between flash states

Kamal Dasu kdasu.kdev at gmail.com
Fri Feb 24 12:16:38 PST 2017


Added flash access synchronization methods spi_nor_get/release_device(). This
change allows spi-nor driver to maintain flash states in spi-nor stucture for
read, write, erase, lock, unlock nor ops. Only when the flash state is FL_READY
a new state is set and spi-nor flash op is initiated. The state change is done
with a spin_lock held and released as soon as the state is changed. Else the
current process for spi-nor transfer is queued till the flash is in FL_READY
state. This change allows us to add mtd layer synchronization when the mtd
resume suspend handlers are added.

Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 69 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |  4 +++
 2 files changed, 73 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 8b71c11..5363807 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -89,6 +89,15 @@ struct flash_info {
 
 #define JEDEC_MFR(info)	((info)->id[0])
 
+/* map table for spi_nor op to flashchip state  */
+static int spi_nor_state[] = {
+	[SPI_NOR_OPS_READ]	= FL_READING,
+	[SPI_NOR_OPS_WRITE]	= FL_WRITING,
+	[SPI_NOR_OPS_ERASE]	= FL_ERASING,
+	[SPI_NOR_OPS_LOCK]	= FL_LOCKING,
+	[SPI_NOR_OPS_UNLOCK]	= FL_UNLOCKING,
+};
+
 static const struct flash_info *spi_nor_match_id(const char *name);
 
 /*
@@ -396,10 +405,64 @@ static int erase_chip(struct spi_nor *nor)
 	return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
 }
 
+/**
+ * spi_nor_get_device - [GENERIC] Get chip for selected access
+ * @param mtd		MTD device structure
+ * @param new_state	the state which is requested
+ *
+ * Get the nor flash device and lock it for exclusive access
+ */
+static int spi_nor_get_device(struct mtd_info *mtd, int new_state)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 * Grab the lock and see if the device is available
+	 */
+	while (1) {
+		spin_lock(&nor->chip_lock);
+		if (nor->state == FL_READY) {
+			nor->state = new_state;
+			spin_unlock(&nor->chip_lock);
+			break;
+		}
+		if (new_state == FL_PM_SUSPENDED) {
+			spin_unlock(&nor->chip_lock);
+			return (nor->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&nor->wq, &wait);
+		spin_unlock(&nor->chip_lock);
+		schedule();
+		remove_wait_queue(&nor->wq, &wait);
+	}
+
+	return 0;
+}
+
+/**
+ * spi_nor_release_device - [GENERIC] release chip
+ * @mtd: MTD device structure
+ *
+ * Release nor flash chip lock and wake up anyone waiting on the device.
+ */
+static void spi_nor_release_device(struct mtd_info *mtd)
+{
+	struct spi_nor *nor = mtd_to_spi_nor(mtd);
+
+	/* Release the controller and the chip */
+	spin_lock(&nor->chip_lock);
+	nor->state = FL_READY;
+	wake_up(&nor->wq);
+	spin_unlock(&nor->chip_lock);
+}
+
 static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
 {
 	int ret = 0;
 
+	spi_nor_get_device(&nor->mtd, spi_nor_state[ops]);
 	mutex_lock(&nor->lock);
 
 	if (nor->prepare) {
@@ -407,6 +470,7 @@ static int spi_nor_lock_and_prep(struct spi_nor *nor, enum spi_nor_ops ops)
 		if (ret) {
 			dev_err(nor->dev, "failed in the preparation.\n");
 			mutex_unlock(&nor->lock);
+			spi_nor_release_device(&nor->mtd);
 			return ret;
 		}
 	}
@@ -418,6 +482,7 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
 	if (nor->unprepare)
 		nor->unprepare(nor, ops);
 	mutex_unlock(&nor->lock);
+	spi_nor_release_device(&nor->mtd);
 }
 
 /*
@@ -1743,6 +1808,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 			return ret;
 	}
 
+	nor->state = FL_READY;
+	init_waitqueue_head(&nor->wq);
+	spin_lock_init(&nor->chip_lock);
+
 	/*
 	 * call init function to send necessary spi-nor read/write config
 	 * commands to nor flash based on above nor settings
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 29a8283..244d98d 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -13,6 +13,7 @@
 #include <linux/bitops.h>
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/flashchip.h>
 
 /*
  * Manufacturer IDs
@@ -210,6 +211,9 @@ struct spi_nor {
 
 	void *priv;
 	const struct flash_info *info;
+	spinlock_t		chip_lock;
+	wait_queue_head_t	wq;
+	flstate_t		state;
 };
 
 static inline void spi_nor_set_flash_node(struct spi_nor *nor,
-- 
1.9.1




More information about the linux-mtd mailing list