From: Kamal Dasu <kdasu.kdev@gmail.com>
To: linux-spi@vger.kernel.org, cyrille.pitchen@atmel.com,
marex@denx.de, broonie@kernel.org
Cc: linux-mtd@lists.infradead.org, f.fainelli@gmail.com,
bcm-kernel-feedback-list@broadcom.com,
Kamal Dasu <kdasu.kdev@gmail.com>
Subject: [PATCH v6 2/3] mtd: spi-nor: Add spi-nor flash device synchronization between flash states
Date: Fri, 24 Feb 2017 15:16:38 -0500 [thread overview]
Message-ID: <1487967399-28967-3-git-send-email-kdasu.kdev@gmail.com> (raw)
In-Reply-To: <1487967399-28967-1-git-send-email-kdasu.kdev@gmail.com>
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@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
WARNING: multiple messages have this Message-ID (diff)
From: Kamal Dasu <kdasu.kdev@gmail.com>
To: linux-spi@vger.kernel.org, cyrille.pitchen@atmel.com,
marex@denx.de, broonie@kernel.org
Cc: bcm-kernel-feedback-list@broadcom.com, f.fainelli@gmail.com,
linux-mtd@lists.infradead.org, Kamal Dasu <kdasu.kdev@gmail.com>
Subject: [PATCH v6 2/3] mtd: spi-nor: Add spi-nor flash device synchronization between flash states
Date: Fri, 24 Feb 2017 15:16:38 -0500 [thread overview]
Message-ID: <1487967399-28967-3-git-send-email-kdasu.kdev@gmail.com> (raw)
In-Reply-To: <1487967399-28967-1-git-send-email-kdasu.kdev@gmail.com>
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@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
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
next prev parent reply other threads:[~2017-02-24 20:17 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-02-24 20:16 [PATCH v6 0/3] Add spi-nor flash device pm support Kamal Dasu
2017-02-24 20:16 ` Kamal Dasu
2017-02-24 20:16 ` [PATCH v6 1/3] mtd: spi-nor: Add spi-nor init function Kamal Dasu
2017-02-24 20:16 ` Kamal Dasu
2017-02-24 20:16 ` Kamal Dasu [this message]
2017-02-24 20:16 ` [PATCH v6 2/3] mtd: spi-nor: Add spi-nor flash device synchronization between flash states Kamal Dasu
2017-02-26 12:18 ` Marek Vasut
2017-02-26 12:18 ` Marek Vasut
2017-03-03 21:38 ` Kamal Dasu
2017-03-03 21:38 ` Kamal Dasu
2017-03-05 1:11 ` Marek Vasut
2017-03-05 1:11 ` Marek Vasut
2017-03-07 23:08 ` Cyrille Pitchen
2017-03-07 23:08 ` Cyrille Pitchen
2017-03-09 20:03 ` Kamal Dasu
2017-03-09 20:03 ` Kamal Dasu
2017-02-24 20:16 ` [PATCH v6 3/3] mtd: spi-nor: Add spi-nor mtd suspend and resume handlers Kamal Dasu
2017-02-24 20:16 ` Kamal Dasu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1487967399-28967-3-git-send-email-kdasu.kdev@gmail.com \
--to=kdasu.kdev@gmail.com \
--cc=bcm-kernel-feedback-list@broadcom.com \
--cc=broonie@kernel.org \
--cc=cyrille.pitchen@atmel.com \
--cc=f.fainelli@gmail.com \
--cc=linux-mtd@lists.infradead.org \
--cc=linux-spi@vger.kernel.org \
--cc=marex@denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.