Hi,
On Mon, Dec 10, 2012 at 03:19:15PM +0000, Jack Mitchell wrote:
On 10/12/12 14:59, Felipe Balbi wrote:
Hi,
On Mon, Dec 10, 2012 at 02:50:16PM +0000, Jack Mitchell wrote:
On Mon, Dec 10, 2012 at 01:23:09PM +0000, Jack Mitchell wrote:
Hi,
I am currently having issues with the SPI driver on the beaglebone
using the 3.7-rc8 kernel[1]. I have probed the SPI pins and I have
found that writing works however reading doesn't. When using DMA the
program seems to lock hard and no data is sent on the bus. I am
testing the bus using spidev and the spidev_test[2] application,
however I first came across spi issues with a custom spi driver which
stopped working when I transitioned from 3.2-psp to 3.7-rc8.
The current output I am seeing from the spidev_test program is just a
series of 0x00 data, which looks to me like no data is getting in at
all. The spidev_test program is not using DMA as the buffer size is
too low, so I forced the dma on when buffer size is > 1 and the
program hangs hard with the system still responding to other
commands.I have briged the pins 18 and 21 on the BeagleBone P9
header.
Has anyone seen issues like this, or if not if someone could please
test the latest 3.7-rc8 from [1] and let me know if it works for them
and the issue is at my end.
To get spidev working with devicetree I applied the patch from [3]
and changed the dtb as in the patch pasted below.
[1] https://github.com/beagleboard/kernel/tree/3.7
[2] http://lxr.linux.no/#linux+v3.6.9/Documentation/spi/spidev_test.c
[3] http://www.mail-archive.com/spi-devel-general@xxxxxxxxxxxxxxxxxxxxx/msg09958.html
do you have any debugging output from that driver ? It would be cool to
see if DMA is at least being kicked properly for small transfers.
When I run the spidev program with dma for transfers > 1, the program
hangs and the only output in dmesg is:
[ 12.613952] libphy: 4a101000.mdio:00 - Link is Up - 100/Full <----
Last line from initial log in [2]
[ 47.669202] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
[ 47.669246] spidev spi1.0: setup mode 0, 8 bits/w, 24000000 Hz max --> 0
[ 47.669260] spidev spi1.0: spi mode 00
[ 47.669283] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
[ 47.669300] spidev spi1.0: setup mode 0, 16 bits/w, 24000000 Hz max --> 0
[ 47.669312] spidev spi1.0: 16 bits per word
[ 47.669330] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
[ 47.669347] spidev spi1.0: setup mode 0, 16 bits/w, 24000000 Hz max --> 0
[ 47.669358] spidev spi1.0: 24000000 Hz (max)
[ 47.673811] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
The initial dmesg statup log is at [2].
can you apply the debugging patch below to spi driver and show me the
output again ?
Note that I'm allowing DMA for as small as 1-byte transfers (as you
needed) and I'm also disabling DMA Request line before calling
complete() as I think the current way could race, but likely wouldn't
cause issues. Anyway, please show me the output.
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 3542fdc..d2b1af2 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -108,7 +108,7 @@ struct omap2_mcspi_dma {
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
* cache operations; better heuristics consider wordsize and bitrate.
*/
-#define DMA_MIN_BYTES 160
+#define DMA_MIN_BYTES 1
/*
@@ -298,10 +298,11 @@ static void omap2_mcspi_rx_callback(void *data)
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
- complete(&mcspi_dma->dma_rx_completion);
-
/* We must disable the DMA RX request */
+ dev_info(&spi->dev, "Disabling RX Request Line\n");
omap2_mcspi_set_dma_req(spi, 1, 0);
+
+ complete(&mcspi_dma->dma_rx_completion);
}
static void omap2_mcspi_tx_callback(void *data)
@@ -310,10 +311,11 @@ static void omap2_mcspi_tx_callback(void *data)
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
- complete(&mcspi_dma->dma_tx_completion);
-
/* We must disable the DMA TX request */
+ dev_info(&spi->dev, "Disabling TX Request Line\n");
omap2_mcspi_set_dma_req(spi, 0, 0);
+
+ complete(&mcspi_dma->dma_tx_completion);
}
static void omap2_mcspi_tx_dma(struct spi_device *spi,
@@ -328,6 +330,7 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
void __iomem *chstat_reg;
struct omap2_mcspi_cs *cs = spi->controller_state;
+ dev_info(&spi->dev, "kicking TX DMA\n");
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
count = xfer->len;
@@ -359,7 +362,9 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
dma_async_issue_pending(mcspi_dma->dma_tx);
omap2_mcspi_set_dma_req(spi, 0, 1);
+ dev_info(&spi->dev, "Waiting for TX Completion\n");
wait_for_completion(&mcspi_dma->dma_tx_completion);
+ dev_info(&spi->dev, "TX Completed\n");
dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
DMA_TO_DEVICE);
@@ -392,6 +397,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
word_len = cs->word_len;
l = mcspi_cached_chconf0(spi);
+ dev_info(&spi->dev, "kicking RX DMA\n");
if (word_len <= 8)
element_count = count;
else if (word_len <= 16)
@@ -428,7 +434,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
dma_async_issue_pending(mcspi_dma->dma_rx);
omap2_mcspi_set_dma_req(spi, 1, 1);
+ dev_info(&spi->dev, "Waiting for RX Completion\n");
wait_for_completion(&mcspi_dma->dma_rx_completion);
+ dev_info(&spi->dev, "RX Completed\n");
dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
DMA_FROM_DEVICE);
omap2_mcspi_set_enable(spi, 0);
It would also be nice to have a clear picture of what "custom spi
driver" you're talking about.
The custom SPI driver is for connecting and reading registers from an
in house FPGA design and can be found at [1]. It's fairly rudimentary
and also in the development stages, I'm very new to Linux kernel
programming so please take that into account :)
no problem ;-)
However it did work flawlessly with 3.2-psp.
yeah, it could be some regression introduced somewhere, or just a bugfix
which was done on 3.2-psp and was missed upstream... annoying when those
happen :-p
Your patch didn't apply cleanly but I hacked it in and got the following:
[ 40.434566] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
[ 40.434609] spidev spi1.0: setup mode 0, 8 bits/w, 24000000 Hz max --> 0
[ 40.434622] spidev spi1.0: spi mode 00
[ 40.434645] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
[ 40.434661] spidev spi1.0: setup mode 0, 16 bits/w, 24000000 Hz max --> 0
[ 40.434673] spidev spi1.0: 16 bits per word
[ 40.434692] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
[ 40.434708] spidev spi1.0: setup mode 0, 16 bits/w, 24000000 Hz max --> 0
[ 40.434720] spidev spi1.0: 24000000 Hz (max)
[ 40.439300] spidev spi1.0: setup: speed 24000000, sample leading
edge, clk normal
[ 40.439397] spidev spi1.0: kicking TX DMA
[ 40.443797] spidev spi1.0: Waiting for TX Completion
so TX dma never completes... perhaps all you need is Shubhro's commit
reordering TX and RX calls ??
commit e47a682ace0cd56eb8e09b806c2b0f034b491520
Author: Shubhrajyoti D <shubhrajyoti@xxxxxx>
Date: Tue Nov 6 14:30:19 2012 +0530
spi: omap2-mcspi: Reorder the wait_for_completion for tx
The commit d7b4394e[Cleanup the omap2_mcspi_txrx_dma function]
changed the wait_for_completion order. Move the wait so that the
rx doesnot wait for the tx to complete.
Reported-and-tested-by: Sørensen, Stefan <Sorensen@xxxxxxxxxxx>
Signed-off-by: Shubhrajyoti D <shubhrajyoti@xxxxxx>
Signed-off-by: Mark Brown <broonie@xxxxxxxxxxxxxxxxxxxxxxxxxxx>
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 3542fdc..b1a651e 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -323,18 +323,13 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
unsigned int count;
- u8 * rx;
const u8 * tx;
- void __iomem *chstat_reg;
- struct omap2_mcspi_cs *cs = spi->controller_state;
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
count = xfer->len;
- rx = xfer->rx_buf;
tx = xfer->tx_buf;
- chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
if (mcspi_dma->dma_tx) {
struct dma_async_tx_descriptor *tx;
@@ -359,19 +354,6 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
dma_async_issue_pending(mcspi_dma->dma_tx);
omap2_mcspi_set_dma_req(spi, 0, 1);
- wait_for_completion(&mcspi_dma->dma_tx_completion);
- dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
- DMA_TO_DEVICE);
-
- /* for TX_ONLY mode, be sure all words have shifted out */
- if (rx == NULL) {
- if (mcspi_wait_for_reg_bit(chstat_reg,
- OMAP2_MCSPI_CHSTAT_TXS) < 0)
- dev_err(&spi->dev, "TXS timed out\n");
- else if (mcspi_wait_for_reg_bit(chstat_reg,
- OMAP2_MCSPI_CHSTAT_EOT) < 0)
- dev_err(&spi->dev, "EOT timed out\n");
- }
}
static unsigned
@@ -492,6 +474,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
struct dma_slave_config cfg;
enum dma_slave_buswidth width;
unsigned es;
+ void __iomem *chstat_reg;
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -526,8 +509,24 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
omap2_mcspi_tx_dma(spi, xfer, cfg);
if (rx != NULL)
- return omap2_mcspi_rx_dma(spi, xfer, cfg, es);
-
+ count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
+
+ if (tx != NULL) {
+ chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
+ wait_for_completion(&mcspi_dma->dma_tx_completion);
+ dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
+ DMA_TO_DEVICE);
+
+ /* for TX_ONLY mode, be sure all words have shifted out */
+ if (rx == NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_TXS) < 0)
+ dev_err(&spi->dev, "TXS timed out\n");
+ else if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_EOT) < 0)
+ dev_err(&spi->dev, "EOT timed out\n");
+ }
+ }
return count;
}
Shubhro, what do you think ? could this be the case ?