From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qk0-x243.google.com ([2607:f8b0:400d:c09::243]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1chMJ6-0001q0-2h for linux-mtd@lists.infradead.org; Fri, 24 Feb 2017 20:17:38 +0000 Received: by mail-qk0-x243.google.com with SMTP id x71so4280627qkb.0 for ; Fri, 24 Feb 2017 12:17:15 -0800 (PST) From: Kamal Dasu 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 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 Message-Id: <1487967399-28967-3-git-send-email-kdasu.kdev@gmail.com> In-Reply-To: <1487967399-28967-1-git-send-email-kdasu.kdev@gmail.com> References: <1487967399-28967-1-git-send-email-kdasu.kdev@gmail.com> List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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 --- 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 #include #include +#include /* * 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 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kamal Dasu 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 Message-ID: <1487967399-28967-3-git-send-email-kdasu.kdev@gmail.com> References: <1487967399-28967-1-git-send-email-kdasu.kdev@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Cc: bcm-kernel-feedback-list@broadcom.com, f.fainelli@gmail.com, linux-mtd@lists.infradead.org, Kamal Dasu To: linux-spi@vger.kernel.org, cyrille.pitchen@atmel.com, marex@denx.de, broonie@kernel.org Return-path: In-Reply-To: <1487967399-28967-1-git-send-email-kdasu.kdev@gmail.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+gldm-linux-mtd-36=gmane.org@lists.infradead.org List-Id: linux-spi.vger.kernel.org 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 --- 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 #include #include +#include /* * 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/