diff options
author | Alek Du <alek.du@intel.com> | 2011-03-30 11:09:55 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-03-30 23:31:48 -0400 |
commit | 3b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155 (patch) | |
tree | 727e17523f0aa432f17caf63a282299ffb3b8191 /drivers/spi | |
parent | 2ff271bf6505038d8c937e73438ea3c80c387439 (diff) |
spi/dw_spi: improve the interrupt mode with the batch ops
leverage the performance gain by change in low level
read/write batch operations
Signed-off-by: Alek Du <alek.du@intel.com>
Signed-off-by: Feng Tang <feng.tang@intel.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/dw_spi.c | 63 |
1 files changed, 16 insertions, 47 deletions
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 7a2a72268f0a..855ac4ae0f22 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c | |||
@@ -190,21 +190,7 @@ static inline u32 rx_max(struct dw_spi *dws) | |||
190 | return min(rx_left, (u32)dw_readw(dws, rxflr)); | 190 | return min(rx_left, (u32)dw_readw(dws, rxflr)); |
191 | } | 191 | } |
192 | 192 | ||
193 | 193 | static void dw_writer(struct dw_spi *dws) | |
194 | static void wait_till_not_busy(struct dw_spi *dws) | ||
195 | { | ||
196 | unsigned long end = jiffies + 1 + usecs_to_jiffies(5000); | ||
197 | |||
198 | while (time_before(jiffies, end)) { | ||
199 | if (!(dw_readw(dws, sr) & SR_BUSY)) | ||
200 | return; | ||
201 | cpu_relax(); | ||
202 | } | ||
203 | dev_err(&dws->master->dev, | ||
204 | "DW SPI: Status keeps busy for 5000us after a read/write!\n"); | ||
205 | } | ||
206 | |||
207 | static int dw_writer(struct dw_spi *dws) | ||
208 | { | 194 | { |
209 | u32 max = tx_max(dws); | 195 | u32 max = tx_max(dws); |
210 | u16 txw = 0; | 196 | u16 txw = 0; |
@@ -220,11 +206,9 @@ static int dw_writer(struct dw_spi *dws) | |||
220 | dw_writew(dws, dr, txw); | 206 | dw_writew(dws, dr, txw); |
221 | dws->tx += dws->n_bytes; | 207 | dws->tx += dws->n_bytes; |
222 | } | 208 | } |
223 | |||
224 | return 1; | ||
225 | } | 209 | } |
226 | 210 | ||
227 | static int dw_reader(struct dw_spi *dws) | 211 | static void dw_reader(struct dw_spi *dws) |
228 | { | 212 | { |
229 | u32 max = rx_max(dws); | 213 | u32 max = rx_max(dws); |
230 | u16 rxw; | 214 | u16 rxw; |
@@ -240,8 +224,6 @@ static int dw_reader(struct dw_spi *dws) | |||
240 | } | 224 | } |
241 | dws->rx += dws->n_bytes; | 225 | dws->rx += dws->n_bytes; |
242 | } | 226 | } |
243 | |||
244 | return dws->rx == dws->rx_end; | ||
245 | } | 227 | } |
246 | 228 | ||
247 | static void *next_transfer(struct dw_spi *dws) | 229 | static void *next_transfer(struct dw_spi *dws) |
@@ -340,35 +322,28 @@ EXPORT_SYMBOL_GPL(dw_spi_xfer_done); | |||
340 | 322 | ||
341 | static irqreturn_t interrupt_transfer(struct dw_spi *dws) | 323 | static irqreturn_t interrupt_transfer(struct dw_spi *dws) |
342 | { | 324 | { |
343 | u16 irq_status, irq_mask = 0x3f; | 325 | u16 irq_status = dw_readw(dws, isr); |
344 | u32 int_level = dws->fifo_len / 2; | ||
345 | u32 left; | ||
346 | 326 | ||
347 | irq_status = dw_readw(dws, isr) & irq_mask; | ||
348 | /* Error handling */ | 327 | /* Error handling */ |
349 | if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) { | 328 | if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) { |
350 | dw_readw(dws, txoicr); | 329 | dw_readw(dws, txoicr); |
351 | dw_readw(dws, rxoicr); | 330 | dw_readw(dws, rxoicr); |
352 | dw_readw(dws, rxuicr); | 331 | dw_readw(dws, rxuicr); |
353 | int_error_stop(dws, "interrupt_transfer: fifo overrun"); | 332 | int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun"); |
354 | return IRQ_HANDLED; | 333 | return IRQ_HANDLED; |
355 | } | 334 | } |
356 | 335 | ||
336 | dw_reader(dws); | ||
337 | if (dws->rx_end == dws->rx) { | ||
338 | spi_mask_intr(dws, SPI_INT_TXEI); | ||
339 | dw_spi_xfer_done(dws); | ||
340 | return IRQ_HANDLED; | ||
341 | } | ||
357 | if (irq_status & SPI_INT_TXEI) { | 342 | if (irq_status & SPI_INT_TXEI) { |
358 | spi_mask_intr(dws, SPI_INT_TXEI); | 343 | spi_mask_intr(dws, SPI_INT_TXEI); |
359 | 344 | dw_writer(dws); | |
360 | left = (dws->tx_end - dws->tx) / dws->n_bytes; | 345 | /* Enable TX irq always, it will be disabled when RX finished */ |
361 | left = (left > int_level) ? int_level : left; | 346 | spi_umask_intr(dws, SPI_INT_TXEI); |
362 | |||
363 | while (left--) | ||
364 | dw_writer(dws); | ||
365 | dw_reader(dws); | ||
366 | |||
367 | /* Re-enable the IRQ if there is still data left to tx */ | ||
368 | if (dws->tx_end > dws->tx) | ||
369 | spi_umask_intr(dws, SPI_INT_TXEI); | ||
370 | else | ||
371 | dw_spi_xfer_done(dws); | ||
372 | } | 347 | } |
373 | 348 | ||
374 | return IRQ_HANDLED; | 349 | return IRQ_HANDLED; |
@@ -377,15 +352,13 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) | |||
377 | static irqreturn_t dw_spi_irq(int irq, void *dev_id) | 352 | static irqreturn_t dw_spi_irq(int irq, void *dev_id) |
378 | { | 353 | { |
379 | struct dw_spi *dws = dev_id; | 354 | struct dw_spi *dws = dev_id; |
380 | u16 irq_status, irq_mask = 0x3f; | 355 | u16 irq_status = dw_readw(dws, isr) & 0x3f; |
381 | 356 | ||
382 | irq_status = dw_readw(dws, isr) & irq_mask; | ||
383 | if (!irq_status) | 357 | if (!irq_status) |
384 | return IRQ_NONE; | 358 | return IRQ_NONE; |
385 | 359 | ||
386 | if (!dws->cur_msg) { | 360 | if (!dws->cur_msg) { |
387 | spi_mask_intr(dws, SPI_INT_TXEI); | 361 | spi_mask_intr(dws, SPI_INT_TXEI); |
388 | /* Never fail */ | ||
389 | return IRQ_HANDLED; | 362 | return IRQ_HANDLED; |
390 | } | 363 | } |
391 | 364 | ||
@@ -492,12 +465,8 @@ static void pump_transfers(unsigned long data) | |||
492 | 465 | ||
493 | switch (bits) { | 466 | switch (bits) { |
494 | case 8: | 467 | case 8: |
495 | dws->n_bytes = 1; | ||
496 | dws->dma_width = 1; | ||
497 | break; | ||
498 | case 16: | 468 | case 16: |
499 | dws->n_bytes = 2; | 469 | dws->n_bytes = dws->dma_width = bits >> 3; |
500 | dws->dma_width = 2; | ||
501 | break; | 470 | break; |
502 | default: | 471 | default: |
503 | printk(KERN_ERR "MRST SPI0: unsupported bits:" | 472 | printk(KERN_ERR "MRST SPI0: unsupported bits:" |
@@ -541,7 +510,7 @@ static void pump_transfers(unsigned long data) | |||
541 | txint_level = dws->fifo_len / 2; | 510 | txint_level = dws->fifo_len / 2; |
542 | txint_level = (templen > txint_level) ? txint_level : templen; | 511 | txint_level = (templen > txint_level) ? txint_level : templen; |
543 | 512 | ||
544 | imask |= SPI_INT_TXEI; | 513 | imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI; |
545 | dws->transfer_handler = interrupt_transfer; | 514 | dws->transfer_handler = interrupt_transfer; |
546 | } | 515 | } |
547 | 516 | ||