Root/target/linux/brcm63xx/patches-3.3/013-spi-bcm63xx-convert-to-the-pump-message-infrastructu.patch

1From cde4384e1037c15e5dd04c68d19c75798b6281dd Mon Sep 17 00:00:00 2001
2From: Florian Fainelli <florian@openwrt.org>
3Date: Fri, 20 Apr 2012 15:37:33 +0200
4Subject: [PATCH] spi/bcm63xx: convert to the pump message infrastructure
5
6This patch converts the bcm63xx SPI driver to use the SPI infrastructure
7pump message queue. Since we were previously sleeping in the SPI
8driver's transfer() function (which is not allowed) this is now fixed as well.
9
10To complete that conversion a certain number of changes have been made:
11- the transfer len is split into multiple hardware transfers in case its
12  size is bigger than the hardware FIFO size
13- the FIFO refill is no longer done in the interrupt context, which was a
14  bad idea leading to quick interrupt handler re-entrancy
15
16Tested-by: Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
17Signed-off-by: Florian Fainelli <florian@openwrt.org>
18Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
19---
20 drivers/spi/spi-bcm63xx.c | 149 +++++++++++++++++++++++++++------------------
21 1 file changed, 89 insertions(+), 60 deletions(-)
22
23--- a/drivers/spi/spi-bcm63xx.c
24+++ b/drivers/spi/spi-bcm63xx.c
25@@ -1,7 +1,7 @@
26 /*
27  * Broadcom BCM63xx SPI controller support
28  *
29- * Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org>
30+ * Copyright (C) 2009-2012 Florian Fainelli <florian@openwrt.org>
31  * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
32  *
33  * This program is free software; you can redistribute it and/or
34@@ -30,6 +30,8 @@
35 #include <linux/spi/spi.h>
36 #include <linux/completion.h>
37 #include <linux/err.h>
38+#include <linux/workqueue.h>
39+#include <linux/pm_runtime.h>
40 
41 #include <bcm63xx_dev_spi.h>
42 
43@@ -96,17 +98,12 @@ static const unsigned bcm63xx_spi_freq_t
44     { 391000, SPI_CLK_0_391MHZ }
45 };
46 
47-static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
48- struct spi_transfer *t)
49+static int bcm63xx_spi_check_transfer(struct spi_device *spi,
50+ struct spi_transfer *t)
51 {
52- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
53     u8 bits_per_word;
54- u8 clk_cfg, reg;
55- u32 hz;
56- int i;
57 
58     bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
59- hz = (t) ? t->speed_hz : spi->max_speed_hz;
60     if (bits_per_word != 8) {
61         dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
62             __func__, bits_per_word);
63@@ -119,6 +116,19 @@ static int bcm63xx_spi_setup_transfer(st
64         return -EINVAL;
65     }
66 
67+ return 0;
68+}
69+
70+static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
71+ struct spi_transfer *t)
72+{
73+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
74+ u32 hz;
75+ u8 clk_cfg, reg;
76+ int i;
77+
78+ hz = (t) ? t->speed_hz : spi->max_speed_hz;
79+
80     /* Find the closest clock configuration */
81     for (i = 0; i < SPI_CLK_MASK; i++) {
82         if (hz >= bcm63xx_spi_freq_table[i][0]) {
83@@ -139,8 +149,6 @@ static int bcm63xx_spi_setup_transfer(st
84     bcm_spi_writeb(bs, reg, SPI_CLK_CFG);
85     dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n",
86         clk_cfg, hz);
87-
88- return 0;
89 }
90 
91 /* the spi->mode bits understood by this driver: */
92@@ -165,7 +173,7 @@ static int bcm63xx_spi_setup(struct spi_
93         return -EINVAL;
94     }
95 
96- ret = bcm63xx_spi_setup_transfer(spi, NULL);
97+ ret = bcm63xx_spi_check_transfer(spi, NULL);
98     if (ret < 0) {
99         dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
100             spi->mode & ~MODEBITS);
101@@ -190,28 +198,29 @@ static void bcm63xx_spi_fill_tx_fifo(str
102     bs->remaining_bytes -= size;
103 }
104 
105-static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
106+static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
107+ struct spi_transfer *t)
108 {
109     struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
110     u16 msg_ctl;
111     u16 cmd;
112 
113+ /* Disable the CMD_DONE interrupt */
114+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
115+
116     dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
117         t->tx_buf, t->rx_buf, t->len);
118 
119     /* Transmitter is inhibited */
120     bs->tx_ptr = t->tx_buf;
121     bs->rx_ptr = t->rx_buf;
122- init_completion(&bs->done);
123 
124     if (t->tx_buf) {
125         bs->remaining_bytes = t->len;
126         bcm63xx_spi_fill_tx_fifo(bs);
127     }
128 
129- /* Enable the command done interrupt which
130- * we use to determine completion of a command */
131- bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
132+ init_completion(&bs->done);
133 
134     /* Fill in the Message control register */
135     msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
136@@ -230,33 +239,76 @@ static int bcm63xx_txrx_bufs(struct spi_
137     cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
138     cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
139     bcm_spi_writew(bs, cmd, SPI_CMD);
140- wait_for_completion(&bs->done);
141 
142- /* Disable the CMD_DONE interrupt */
143- bcm_spi_writeb(bs, 0, SPI_INT_MASK);
144+ /* Enable the CMD_DONE interrupt */
145+ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
146 
147     return t->len - bs->remaining_bytes;
148 }
149 
150-static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m)
151+static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
152 {
153- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
154- struct spi_transfer *t;
155- int ret = 0;
156+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
157 
158- if (unlikely(list_empty(&m->transfers)))
159- return -EINVAL;
160+ pm_runtime_get_sync(&bs->pdev->dev);
161 
162- if (bs->stopping)
163- return -ESHUTDOWN;
164+ return 0;
165+}
166+
167+static int bcm63xx_spi_unprepare_transfer(struct spi_master *master)
168+{
169+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
170+
171+ pm_runtime_put(&bs->pdev->dev);
172+
173+ return 0;
174+}
175+
176+static int bcm63xx_spi_transfer_one(struct spi_master *master,
177+ struct spi_message *m)
178+{
179+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
180+ struct spi_transfer *t;
181+ struct spi_device *spi = m->spi;
182+ int status = 0;
183+ unsigned int timeout = 0;
184 
185     list_for_each_entry(t, &m->transfers, transfer_list) {
186- ret += bcm63xx_txrx_bufs(spi, t);
187- }
188+ unsigned int len = t->len;
189+ u8 rx_tail;
190 
191- m->complete(m->context);
192+ status = bcm63xx_spi_check_transfer(spi, t);
193+ if (status < 0)
194+ goto exit;
195+
196+ /* configure adapter for a new transfer */
197+ bcm63xx_spi_setup_transfer(spi, t);
198+
199+ while (len) {
200+ /* send the data */
201+ len -= bcm63xx_txrx_bufs(spi, t);
202+
203+ timeout = wait_for_completion_timeout(&bs->done, HZ);
204+ if (!timeout) {
205+ status = -ETIMEDOUT;
206+ goto exit;
207+ }
208+
209+ /* read out all data */
210+ rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
211+
212+ /* Read out all the data */
213+ if (rx_tail)
214+ memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
215+ }
216+
217+ m->actual_length += t->len;
218+ }
219+exit:
220+ m->status = status;
221+ spi_finalize_current_message(master);
222 
223- return ret;
224+ return 0;
225 }
226 
227 /* This driver supports single master mode only. Hence
228@@ -267,39 +319,15 @@ static irqreturn_t bcm63xx_spi_interrupt
229     struct spi_master *master = (struct spi_master *)dev_id;
230     struct bcm63xx_spi *bs = spi_master_get_devdata(master);
231     u8 intr;
232- u16 cmd;
233 
234     /* Read interupts and clear them immediately */
235     intr = bcm_spi_readb(bs, SPI_INT_STATUS);
236     bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
237     bcm_spi_writeb(bs, 0, SPI_INT_MASK);
238 
239- /* A tansfer completed */
240- if (intr & SPI_INTR_CMD_DONE) {
241- u8 rx_tail;
242-
243- rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
244-
245- /* Read out all the data */
246- if (rx_tail)
247- memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
248-
249- /* See if there is more data to send */
250- if (bs->remaining_bytes > 0) {
251- bcm63xx_spi_fill_tx_fifo(bs);
252-
253- /* Start the transfer */
254- bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT,
255- SPI_MSG_CTL);
256- cmd = bcm_spi_readw(bs, SPI_CMD);
257- cmd |= SPI_CMD_START_IMMEDIATE;
258- cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
259- bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
260- bcm_spi_writew(bs, cmd, SPI_CMD);
261- } else {
262- complete(&bs->done);
263- }
264- }
265+ /* A transfer completed */
266+ if (intr & SPI_INTR_CMD_DONE)
267+ complete(&bs->done);
268 
269     return IRQ_HANDLED;
270 }
271@@ -345,7 +373,6 @@ static int __devinit bcm63xx_spi_probe(s
272     }
273 
274     bs = spi_master_get_devdata(master);
275- init_completion(&bs->done);
276 
277     platform_set_drvdata(pdev, master);
278     bs->pdev = pdev;
279@@ -379,7 +406,9 @@ static int __devinit bcm63xx_spi_probe(s
280     master->bus_num = pdata->bus_num;
281     master->num_chipselect = pdata->num_chipselect;
282     master->setup = bcm63xx_spi_setup;
283- master->transfer = bcm63xx_transfer;
284+ master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
285+ master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
286+ master->transfer_one_message = bcm63xx_spi_transfer_one;
287     bs->speed_hz = pdata->speed_hz;
288     bs->stopping = 0;
289     bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
290

Archive Download this file



interactive