spi: dw: Fix off-by-one for checking fifo depth
PATCH 1/1 spi: dw: Fix off-by-one for checking fifo depth
The fifo depth could be from 2 to 256 from HW spec, so fix off-by-one for checking fifo depth.
Without this patch, fifo is 258 after for loop iteration for the "no-match" case. So below line does not catch the "no-match" case.
dws->fifo_len = (fifo == 257) ? 0 : fifo;
---
Hi,
I don't have this hardware handy, so please test it.
BTW, I'm wondering if it make sense to set dws->fifo_len to 0. Isn't it suppose to be 2 ~ 256?
Thanks.
drivers/spi/spi-dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-dw.c +1 -1
@@ -621,7 +621,7 @@ static void spi_hw_init(struct dw_spi *dws)if (!dws->fifo_len) {u32 fifo; -for (fifo =2 ; fifo <=257 ; fifo++) { +for (fifo =2 ; fifo <=256 ; fifo++) {dw_writew (dws,DW_SPI_TXFLTR , fifo);if (fifo !=dw_readw (dws,DW_SPI_TXFLTR ))break ;
Signature · 8 lines
1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 5 lines · Axel Lin
The fifo depth could be from 2 to 256 from HW spec, so fix off-by-one for checking fifo depth.
Without this patch, fifo is 258 after for loop iteration for the "no-match" case. So below line does not catch the "no-match" case.dws->fifo_len = (fifo == 257) ? 0 : fifo;
Seems reasonable, but never tried because in case of Medfield device we have fifo size defined.
I would try this in January.
Quoted 8 lines
Signed-off-by Axel Lin <[email protected]>---
Hi,
I don't have this hardware handy, so please test it.BTW, I'm wondering if it make sense to set
dws->fifo_lento 0. Isn't it suppose to be 2 ~ 256?
For me it sounds like we have broken HW or wrong configuration (of the driver). If kernel would have crashed in that case the investigation has to be done.
Maybe warning message or even error if FIFO size doesn't lie in the range?
Quoted 18 lines
Thanks.
drivers/spi/spi-dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/spi/spi-dw.c +1
-1@@ -621,7 +621,7 @@ static void spi_hw_init(struct dw_spi *dws)if (!dws->fifo_len) {u32 fifo; -for (fifo =2 ; fifo <=257 ; fifo++) { +for (fifo =2 ; fifo <=256 ; fifo++) {dw_writew (dws,DW_SPI_TXFLTR , fifo);if (fifo !=dw_readw (dws,DW_SPI_TXFLTR ))break ;
Signature · 7 lines
Andy Shevchenko <[email protected]> Intel Finland Oy -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 1418989567.17201.71.camel-VuQAYsv1563Yd54FQh9/[email protected]
2014-12-19 19:46 GMT+08:00 Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]>:
Quoted 11 lines · Axel Lin
Quoted 5 lines
The fifo depth could be from 2 to 256 from HW spec, so fix off-by-one for checking fifo depth.
Without this patch, fifo is 258 after for loop iteration for the "no-match" case. So below line does not catch the "no-match" case.dws->fifo_len = (fifo == 257) ? 0 : fifo;Seems reasonable, but never tried because in case of Medfield device we have fifo size defined.
I would try this in January.
hi Andy,
I check the code again and I think what current code does is:
It tries to find the highest valid fifo depth so it checks the value it wrote to DW_SPI_TXFLTR. I think the valid value range is 2 ~ 256.
So it will break out when writing 257 to DW_SPI_TXFLTR.
There is an off-by-one in dws->fifo_len setting because it assumes the latest register write fails so the latest valid value is fifo - 1.
So I think you can set dws->fifo_len to 0 to test current behavior first.
I guess below change should work, please test this instead my previous patch.
drivers/spi/spi-dw.c +2 -2
@@ -621,13 +621,13 @@ static void spi_hw_init(struct dw_spi *dws)if (!dws->fifo_len) {u32 fifo; -for (fifo =2 ; fifo <=257 ; fifo++) { +for (fifo =2 ; fifo <=256 ; fifo++) {dw_writew (dws,DW_SPI_TXFLTR , fifo);if (fifo !=dw_readw (dws,DW_SPI_TXFLTR ))break ; } - dws->fifo_len = (fifo ==257 ) ?0 : fifo; + dws->fifo_len = (fifo ==2 ) ?0 : fifo -1 ;dw_writew (dws,DW_SPI_TXFLTR ,0 ); } }
Regards,
Axel
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): CAFRkauAeny6cSrqDq=NpNrx2eyZ8sCzoWzH_KpTxTreuXuWwMQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org
Quoted 11 lines · Axel Lin
2014-12-19 19:46 GMT+08:00 Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]>:
Quoted 10 lines · Axel Lin
Quoted 5 lines
The fifo depth could be from 2 to 256 from HW spec, so fix off-by-one for checking fifo depth.
Without this patch, fifo is 258 after for loop iteration for the "no-match" case. So below line does not catch the "no-match" case.dws->fifo_len = (fifo == 257) ? 0 : fifo;Seems reasonable, but never tried because in case of Medfield device we have fifo size defined.
Quoted 8 lines
Quoted 1 line
I would try this in January.
hi Andy,
I check the code again and I think what current code does is:
It tries to find the highest valid fifo depth so it checks the value it wrote toDW_SPI_TXFLTR. I think the valid value range is 2 ~ 256.
So it will break out when writing 257 toDW_SPI_TXFLTR.
I think it will be considered as 1 by HW that kinda not what we want.
Quoted 7 lines
There is an off-by-one in
dws->fifo_lensetting because it assumes the latest register write fails so the latest valid value is fifo - 1.So I think you can set
dws->fifo_lento 0 to test current behavior first.I guess below change should work, please test this instead my previous patch.
Something wrong with formatting below, but don't worry I applied it manually and retested.
Quoted 10 lines
drivers/spi/spi-dw.c +1
-1@@ -621,13 +621,13 @@ static void spi_hw_init(struct dw_spi *dws)if (!dws->fifo_len) {u32 fifo; -for (fifo =2 ; fifo <=257 ; fifo++) { +for (fifo =2 ; fifo <=256 ; fifo++) {
drivers/spi/spi-dw.c static void spi_hw_init(struct dw_spi *dws) · line 633
Quoted 10 lines
drivers/spi/spi-dw.c +1
-1dw_writew (dws,DW_SPI_TXFLTR , fifo);if (fifo !=dw_readw (dws,DW_SPI_TXFLTR ))break ; } - dws->fifo_len = (fifo ==257 ) ?0 : fifo; + dws->fifo_len = (fifo ==2 ) ?0 : fifo -1 ;dw_writew (dws,DW_SPI_TXFLTR ,0 ); } }
So, my diff looks like:
drivers/spi/spi-dw.c +7 -6
@@ -595,7 +595,7 @@ static void dw_spi_cleanup(struct spi_device *spi) }/* Restart the controller, disable all interrupts, clean rx fifo */ -static void spi_hw_init (struct dw_spi *dws) +static void spi_hw_init (struct device *dev,struct dw_spi *dws) {dw_spi_disable_intr (dws);
@@ -606,14 +606,15 @@ static void spi_hw_init(struct dw_spi *dws)if (!dws->fifo_len) {u32 fifo; -for (fifo =2 ; fifo <=257 ; fifo++) { +for (fifo =2 ; fifo <=256 ; fifo++) {dw_writew (dws,DW_SPI_TXFLTR , fifo);if (fifo !=dw_readw (dws,DW_SPI_TXFLTR ))break ; } - - dws->fifo_len = (fifo ==257 ) ?0 : fifo;dw_writew (dws,DW_SPI_TXFLTR ,0 ); + + dws->fifo_len = (fifo ==2 ) ?0 : fifo -1 ; +dev_dbg (dev,"Detected FIFO size: %u bytes\n" , dws->fifo_len); } }
@@ -653,7 +654,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->dev.of_node = dev->of_node;/* Basic HW init */ -spi_hw_init (dws); +spi_hw_init (dev, dws);if (dws->dma_ops && dws->dma_ops->dma_init) { ret = dws->dma_ops->dma_init (dws);
@@ -718,7 +719,7 @@ int dw_spi_resume_host(struct dw_spi *dws) {int ret; -spi_hw_init (dws); +spi_hw_init (&dws->master->dev, dws); ret =spi_master_resume (dws->master);if (ret)dev_err (&dws->master->dev,"fail to start queue (%d)\n" , ret);
Feel free to amend it if needed. For the fix itself get my
Reviewed-and-tested-by: Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]>
Signature · 7 lines
Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/[email protected]> Intel Finland Oy -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html