aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorAbhishek Sahu <absahu@codeaurora.org>2017-08-17 17:37:40 +0530
committerBoris Brezillon <boris.brezillon@free-electrons.com>2017-08-23 16:49:26 +0200
commitcb80f1140db6ad2cb6841ad656cc6b779b4b58be (patch)
tree7d22820d0252c545ace18620bb182e8ffc8eceb1 /drivers/mtd
parentmtd: nand: qcom: DMA mapping support for register read buffer (diff)
downloadlinux-dev-cb80f1140db6ad2cb6841ad656cc6b779b4b58be.tar.xz
linux-dev-cb80f1140db6ad2cb6841ad656cc6b779b4b58be.zip
mtd: nand: qcom: allocate BAM transaction
- The BAM transaction is the core data structure which will be used for all the data transfers in QPIC NAND. Since the core framework in nand_base.c is serializing all the NAND requests so allocating BAM transaction before every transfer will be overhead. The memory for it be allocated during probe time and before every transfer, it will be cleared. - The BAM transaction contains the array of command and data scatter gather list and indexes. For every transfer, all the resource will be taken from BAM transaction. - The size of the buffer used for BAM transactions is calculated based on the NAND device with the maximum page size, among all the devices connected to the controller. Reviewed-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/qcom_nandc.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index 590fc1dd556e..4f8306e84537 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -177,6 +177,32 @@
#define ECC_BCH_4BIT BIT(2)
#define ECC_BCH_8BIT BIT(3)
+#define QPIC_PER_CW_CMD_SGL 32
+#define QPIC_PER_CW_DATA_SGL 8
+
+/*
+ * This data type corresponds to the BAM transaction which will be used for all
+ * NAND transfers.
+ * @cmd_sgl - sgl for NAND BAM command pipe
+ * @data_sgl - sgl for NAND BAM consumer/producer pipe
+ * @cmd_sgl_pos - current index in command sgl.
+ * @cmd_sgl_start - start index in command sgl.
+ * @tx_sgl_pos - current index in data sgl for tx.
+ * @tx_sgl_start - start index in data sgl for tx.
+ * @rx_sgl_pos - current index in data sgl for rx.
+ * @rx_sgl_start - start index in data sgl for rx.
+ */
+struct bam_transaction {
+ struct scatterlist *cmd_sgl;
+ struct scatterlist *data_sgl;
+ u32 cmd_sgl_pos;
+ u32 cmd_sgl_start;
+ u32 tx_sgl_pos;
+ u32 tx_sgl_start;
+ u32 rx_sgl_pos;
+ u32 rx_sgl_start;
+};
+
struct desc_info {
struct list_head node;
@@ -243,6 +269,8 @@ struct nandc_regs {
* @cmd1/vld: some fixed controller register values
* @props: properties of current NAND controller,
* initialized via DT match data
+ * @max_cwperpage: maximum QPIC codewords required. calculated
+ * from all connected NAND devices pagesize
*/
struct qcom_nand_controller {
struct nand_hw_control controller;
@@ -273,11 +301,13 @@ struct qcom_nand_controller {
};
struct list_head desc_list;
+ struct bam_transaction *bam_txn;
u8 *data_buffer;
int buf_size;
int buf_count;
int buf_start;
+ unsigned int max_cwperpage;
__le32 *reg_read_buf;
dma_addr_t reg_read_dma;
@@ -350,6 +380,44 @@ struct qcom_nandc_props {
bool is_bam;
};
+/* Frees the BAM transaction memory */
+static void free_bam_transaction(struct qcom_nand_controller *nandc)
+{
+ struct bam_transaction *bam_txn = nandc->bam_txn;
+
+ devm_kfree(nandc->dev, bam_txn);
+}
+
+/* Allocates and Initializes the BAM transaction */
+static struct bam_transaction *
+alloc_bam_transaction(struct qcom_nand_controller *nandc)
+{
+ struct bam_transaction *bam_txn;
+ size_t bam_txn_size;
+ unsigned int num_cw = nandc->max_cwperpage;
+ void *bam_txn_buf;
+
+ bam_txn_size =
+ sizeof(*bam_txn) + num_cw *
+ ((sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) +
+ (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL));
+
+ bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL);
+ if (!bam_txn_buf)
+ return NULL;
+
+ bam_txn = bam_txn_buf;
+ bam_txn_buf += sizeof(*bam_txn);
+
+ bam_txn->cmd_sgl = bam_txn_buf;
+ bam_txn_buf +=
+ sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw;
+
+ bam_txn->data_sgl = bam_txn_buf;
+
+ return bam_txn;
+}
+
static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
{
return container_of(chip, struct qcom_nand_host, chip);
@@ -1920,6 +1988,8 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host)
mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops);
cwperpage = mtd->writesize / ecc->size;
+ nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage,
+ cwperpage);
/*
* DATA_UD_BYTES varies based on whether the read/write command protects
@@ -2054,6 +2124,20 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc)
dev_err(nandc->dev, "failed to request cmd channel\n");
return -ENODEV;
}
+
+ /*
+ * Initially allocate BAM transaction to read ONFI param page.
+ * After detecting all the devices, this BAM transaction will
+ * be freed and the next BAM tranasction will be allocated with
+ * maximum codeword size
+ */
+ nandc->max_cwperpage = 1;
+ nandc->bam_txn = alloc_bam_transaction(nandc);
+ if (!nandc->bam_txn) {
+ dev_err(nandc->dev,
+ "failed to allocate bam transaction\n");
+ return -ENOMEM;
+ }
} else {
nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
if (!nandc->chan) {
@@ -2211,6 +2295,16 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc)
if (list_empty(&nandc->host_list))
return -ENODEV;
+ if (nandc->props->is_bam) {
+ free_bam_transaction(nandc);
+ nandc->bam_txn = alloc_bam_transaction(nandc);
+ if (!nandc->bam_txn) {
+ dev_err(nandc->dev,
+ "failed to allocate bam transaction\n");
+ return -ENOMEM;
+ }
+ }
+
list_for_each_entry_safe(host, tmp, &nandc->host_list, node) {
ret = qcom_nand_mtd_register(nandc, host, child);
if (ret) {