Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: spi-ti-qspi: switch to polling mode for better r/w performance

Currently word completion interrupt is fired for transfer of every
word(8bit to 128bit in size). This adds a lot of overhead, and decreases
r/w throughput. It hardly takes 3us(@48MHz) for 128bit r/w to complete,
hence its better to poll on word complete bit to be set in
QSPI_SPI_STATUS_REG instead of using interrupts.
This increases the throughput by 30% in both read and write case.

So, switch to polling mode instead of interrupts to determine completion
of word transfer.

Signed-off-by: Vignesh R <vigneshr@ti.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Vignesh R and committed by
Mark Brown
57c2ecd9 6ff33f39

+20 -54
+20 -54
drivers/spi/spi-ti-qspi.c
··· 39 39 }; 40 40 41 41 struct ti_qspi { 42 - struct completion transfer_complete; 43 - 44 42 /* list synchronization */ 45 43 struct mutex list_lock; 46 44 ··· 60 62 61 63 #define QSPI_PID (0x0) 62 64 #define QSPI_SYSCONFIG (0x10) 63 - #define QSPI_INTR_STATUS_RAW_SET (0x20) 64 - #define QSPI_INTR_STATUS_ENABLED_CLEAR (0x24) 65 - #define QSPI_INTR_ENABLE_SET_REG (0x28) 66 - #define QSPI_INTR_ENABLE_CLEAR_REG (0x2c) 67 65 #define QSPI_SPI_CLOCK_CNTRL_REG (0x40) 68 66 #define QSPI_SPI_DC_REG (0x44) 69 67 #define QSPI_SPI_CMD_REG (0x48) ··· 91 97 #define QSPI_RD_DUAL (3 << 16) 92 98 #define QSPI_RD_QUAD (7 << 16) 93 99 #define QSPI_INVAL (4 << 16) 94 - #define QSPI_WC_CMD_INT_EN (1 << 14) 95 100 #define QSPI_FLEN(n) ((n - 1) << 0) 96 101 #define QSPI_WLEN_MAX_BITS 128 97 102 #define QSPI_WLEN_MAX_BYTES 16 ··· 98 105 /* STATUS REGISTER */ 99 106 #define BUSY 0x01 100 107 #define WC 0x02 101 - 102 - /* INTERRUPT REGISTER */ 103 - #define QSPI_WC_INT_EN (1 << 1) 104 - #define QSPI_WC_INT_DISABLE (1 << 1) 105 108 106 109 /* Device Control */ 107 110 #define QSPI_DD(m, n) (m << (3 + n * 8)) ··· 206 217 return stat & BUSY; 207 218 } 208 219 220 + static inline int ti_qspi_poll_wc(struct ti_qspi *qspi) 221 + { 222 + u32 stat; 223 + unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; 224 + 225 + do { 226 + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 227 + if (stat & WC) 228 + return 0; 229 + cpu_relax(); 230 + } while (time_after(timeout, jiffies)); 231 + 232 + stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 233 + if (stat & WC) 234 + return 0; 235 + return -ETIMEDOUT; 236 + } 237 + 209 238 static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) 210 239 { 211 240 int wlen, count, xfer_len; ··· 282 275 } 283 276 284 277 ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 285 - if (!wait_for_completion_timeout(&qspi->transfer_complete, 286 - QSPI_COMPLETION_TIMEOUT)) { 278 + if (ti_qspi_poll_wc(qspi)) { 287 279 dev_err(qspi->dev, "write timed out\n"); 288 280 return -ETIMEDOUT; 289 281 } ··· 321 315 return -EBUSY; 322 316 323 317 ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 324 - if (!wait_for_completion_timeout(&qspi->transfer_complete, 325 - QSPI_COMPLETION_TIMEOUT)) { 318 + if (ti_qspi_poll_wc(qspi)) { 326 319 dev_err(qspi->dev, "read timed out\n"); 327 320 return -ETIMEDOUT; 328 321 } ··· 393 388 qspi->cmd = 0; 394 389 qspi->cmd |= QSPI_EN_CS(spi->chip_select); 395 390 qspi->cmd |= QSPI_FLEN(frame_length); 396 - qspi->cmd |= QSPI_WC_CMD_INT_EN; 397 391 398 - ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG); 399 392 ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG); 400 393 401 394 mutex_lock(&qspi->list_lock); ··· 419 416 ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); 420 417 421 418 return status; 422 - } 423 - 424 - static irqreturn_t ti_qspi_isr(int irq, void *dev_id) 425 - { 426 - struct ti_qspi *qspi = dev_id; 427 - u16 int_stat; 428 - u32 stat; 429 - 430 - irqreturn_t ret = IRQ_HANDLED; 431 - 432 - int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR); 433 - stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 434 - 435 - if (!int_stat) { 436 - dev_dbg(qspi->dev, "No IRQ triggered\n"); 437 - ret = IRQ_NONE; 438 - goto out; 439 - } 440 - 441 - ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, 442 - QSPI_INTR_STATUS_ENABLED_CLEAR); 443 - if (stat & WC) 444 - complete(&qspi->transfer_complete); 445 - out: 446 - return ret; 447 419 } 448 420 449 421 static int ti_qspi_runtime_resume(struct device *dev) ··· 529 551 } 530 552 } 531 553 532 - ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0, 533 - dev_name(&pdev->dev), qspi); 534 - if (ret < 0) { 535 - dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", 536 - irq); 537 - goto free_master; 538 - } 539 - 540 554 qspi->fclk = devm_clk_get(&pdev->dev, "fck"); 541 555 if (IS_ERR(qspi->fclk)) { 542 556 ret = PTR_ERR(qspi->fclk); 543 557 dev_err(&pdev->dev, "could not get clk: %d\n", ret); 544 558 } 545 - 546 - init_completion(&qspi->transfer_complete); 547 559 548 560 pm_runtime_use_autosuspend(&pdev->dev); 549 561 pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT); ··· 563 595 dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); 564 596 return ret; 565 597 } 566 - 567 - ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); 568 598 569 599 pm_runtime_put(qspi->dev); 570 600 pm_runtime_disable(&pdev->dev);