aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2014-02-02 08:47:47 -0500
committerMark Brown <broonie@linaro.org>2014-02-04 15:31:49 -0500
commit6ad45a27cbe343ec8d7888e5edf6335499a4b555 (patch)
treeb24da97af83e92bdb2a1e0805b8c80d6baedb14e /drivers/spi
parent3a2eba9bd0a6447dfbc01635e4cd0689f5f2bdad (diff)
spi: Make core DMA mapping functions generate scatterlists
We cannot unconditionally use dma_map_single() to map data for use with SPI since transfers may exceed a page and virtual addresses may not be provided with physically contiguous pages. Further, addresses allocated using vmalloc() need to be mapped differently to other addresses. Currently only the MXS driver handles all this, a few drivers do handle the possibility that buffers may not be physically contiguous which is the main potential problem but many don't even do that. Factoring this out into the core will make it easier for drivers to do a good job so if the driver is using the core DMA code then generate a scatterlist instead of mapping to a single address so do that. This code is mainly based on a combination of the existing code in the MXS and PXA2xx drivers. In future we should be able to extend it to allow the core to concatenate adjacent transfers if they are compatible, improving performance. Currently for simplicity clients are not allowed to use the scatterlist when they do DMA mapping, in the future the existing single address mappings will be replaced with use of the scatterlist most likely as part of pre-verifying transfers. This change makes it mandatory to use scatterlists when using the core DMA mapping so update the s3c64xx driver to do this when used with dmaengine. Doing so makes the code more ugly but it is expected that the old s3c-dma code can be removed very soon. Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-s3c64xx.c14
-rw-r--r--drivers/spi/spi.c101
2 files changed, 87 insertions, 28 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index e515b8a6f590..25c9bd409a87 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -381,7 +381,7 @@ static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
381#else 381#else
382 382
383static void prepare_dma(struct s3c64xx_spi_dma_data *dma, 383static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
384 unsigned len, dma_addr_t buf) 384 struct sg_table *sgt)
385{ 385{
386 struct s3c64xx_spi_driver_data *sdd; 386 struct s3c64xx_spi_driver_data *sdd;
387 struct dma_slave_config config; 387 struct dma_slave_config config;
@@ -407,8 +407,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
407 dmaengine_slave_config(dma->ch, &config); 407 dmaengine_slave_config(dma->ch, &config);
408 } 408 }
409 409
410 desc = dmaengine_prep_slave_single(dma->ch, buf, len, 410 desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
411 dma->direction, DMA_PREP_INTERRUPT); 411 dma->direction, DMA_PREP_INTERRUPT);
412 412
413 desc->callback = s3c64xx_spi_dmacb; 413 desc->callback = s3c64xx_spi_dmacb;
414 desc->callback_param = dma; 414 desc->callback_param = dma;
@@ -515,7 +515,11 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
515 chcfg |= S3C64XX_SPI_CH_TXCH_ON; 515 chcfg |= S3C64XX_SPI_CH_TXCH_ON;
516 if (dma_mode) { 516 if (dma_mode) {
517 modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; 517 modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
518#ifndef CONFIG_S3C_DMA
519 prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
520#else
518 prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); 521 prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
522#endif
519 } else { 523 } else {
520 switch (sdd->cur_bpw) { 524 switch (sdd->cur_bpw) {
521 case 32: 525 case 32:
@@ -547,7 +551,11 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
547 writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) 551 writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
548 | S3C64XX_SPI_PACKET_CNT_EN, 552 | S3C64XX_SPI_PACKET_CNT_EN,
549 regs + S3C64XX_SPI_PACKET_CNT); 553 regs + S3C64XX_SPI_PACKET_CNT);
554#ifndef CONFIG_S3C_DMA
555 prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
556#else
550 prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); 557 prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
558#endif
551 } 559 }
552 } 560 }
553 561
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index bb7cf561c311..49313dd0a144 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -582,13 +582,70 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
582 spi->master->set_cs(spi, !enable); 582 spi->master->set_cs(spi, !enable);
583} 583}
584 584
585static int spi_map_buf(struct spi_master *master, struct device *dev,
586 struct sg_table *sgt, void *buf, size_t len,
587 enum dma_data_direction dir)
588{
589 const bool vmalloced_buf = is_vmalloc_addr(buf);
590 const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len;
591 const int sgs = DIV_ROUND_UP(len, desc_len);
592 struct page *vm_page;
593 void *sg_buf;
594 size_t min;
595 int i, ret;
596
597 ret = sg_alloc_table(sgt, sgs, GFP_KERNEL);
598 if (ret != 0)
599 return ret;
600
601 for (i = 0; i < sgs; i++) {
602 min = min_t(size_t, len, desc_len);
603
604 if (vmalloced_buf) {
605 vm_page = vmalloc_to_page(buf);
606 if (!vm_page) {
607 sg_free_table(sgt);
608 return -ENOMEM;
609 }
610 sg_buf = page_address(vm_page) +
611 ((size_t)buf & ~PAGE_MASK);
612 } else {
613 sg_buf = buf;
614 }
615
616 sg_set_buf(&sgt->sgl[i], sg_buf, min);
617
618 buf += min;
619 len -= min;
620 }
621
622 ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
623 if (ret < 0) {
624 sg_free_table(sgt);
625 return ret;
626 }
627
628 sgt->nents = ret;
629
630 return 0;
631}
632
633static void spi_unmap_buf(struct spi_master *master, struct device *dev,
634 struct sg_table *sgt, enum dma_data_direction dir)
635{
636 if (sgt->orig_nents) {
637 dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
638 sg_free_table(sgt);
639 }
640}
641
585static int spi_map_msg(struct spi_master *master, struct spi_message *msg) 642static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
586{ 643{
587 struct device *dev = master->dev.parent;
588 struct device *tx_dev, *rx_dev; 644 struct device *tx_dev, *rx_dev;
589 struct spi_transfer *xfer; 645 struct spi_transfer *xfer;
590 void *tmp; 646 void *tmp;
591 size_t max_tx, max_rx; 647 size_t max_tx, max_rx;
648 int ret;
592 649
593 if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { 650 if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) {
594 max_tx = 0; 651 max_tx = 0;
@@ -631,7 +688,7 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
631 } 688 }
632 } 689 }
633 690
634 if (msg->is_dma_mapped || !master->can_dma) 691 if (!master->can_dma)
635 return 0; 692 return 0;
636 693
637 tx_dev = &master->dma_tx->dev->device; 694 tx_dev = &master->dma_tx->dev->device;
@@ -642,25 +699,21 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
642 continue; 699 continue;
643 700
644 if (xfer->tx_buf != NULL) { 701 if (xfer->tx_buf != NULL) {
645 xfer->tx_dma = dma_map_single(tx_dev, 702 ret = spi_map_buf(master, tx_dev, &xfer->tx_sg,
646 (void *)xfer->tx_buf, 703 (void *)xfer->tx_buf, xfer->len,
647 xfer->len, 704 DMA_TO_DEVICE);
648 DMA_TO_DEVICE); 705 if (ret != 0)
649 if (dma_mapping_error(dev, xfer->tx_dma)) { 706 return ret;
650 dev_err(dev, "dma_map_single Tx failed\n");
651 return -ENOMEM;
652 }
653 } 707 }
654 708
655 if (xfer->rx_buf != NULL) { 709 if (xfer->rx_buf != NULL) {
656 xfer->rx_dma = dma_map_single(rx_dev, 710 ret = spi_map_buf(master, rx_dev, &xfer->rx_sg,
657 xfer->rx_buf, xfer->len, 711 xfer->rx_buf, xfer->len,
658 DMA_FROM_DEVICE); 712 DMA_FROM_DEVICE);
659 if (dma_mapping_error(dev, xfer->rx_dma)) { 713 if (ret != 0) {
660 dev_err(dev, "dma_map_single Rx failed\n"); 714 spi_unmap_buf(master, tx_dev, &xfer->tx_sg,
661 dma_unmap_single(tx_dev, xfer->tx_dma, 715 DMA_TO_DEVICE);
662 xfer->len, DMA_TO_DEVICE); 716 return ret;
663 return -ENOMEM;
664 } 717 }
665 } 718 }
666 } 719 }
@@ -675,7 +728,7 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
675 struct spi_transfer *xfer; 728 struct spi_transfer *xfer;
676 struct device *tx_dev, *rx_dev; 729 struct device *tx_dev, *rx_dev;
677 730
678 if (!master->cur_msg_mapped || msg->is_dma_mapped || !master->can_dma) 731 if (!master->cur_msg_mapped || !master->can_dma)
679 return 0; 732 return 0;
680 733
681 tx_dev = &master->dma_tx->dev->device; 734 tx_dev = &master->dma_tx->dev->device;
@@ -685,12 +738,8 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
685 if (!master->can_dma(master, msg->spi, xfer)) 738 if (!master->can_dma(master, msg->spi, xfer))
686 continue; 739 continue;
687 740
688 if (xfer->rx_buf) 741 spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
689 dma_unmap_single(rx_dev, xfer->rx_dma, xfer->len, 742 spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
690 DMA_FROM_DEVICE);
691 if (xfer->tx_buf)
692 dma_unmap_single(tx_dev, xfer->tx_dma, xfer->len,
693 DMA_TO_DEVICE);
694 } 743 }
695 744
696 return 0; 745 return 0;
@@ -1503,6 +1552,8 @@ int spi_register_master(struct spi_master *master)
1503 mutex_init(&master->bus_lock_mutex); 1552 mutex_init(&master->bus_lock_mutex);
1504 master->bus_lock_flag = 0; 1553 master->bus_lock_flag = 0;
1505 init_completion(&master->xfer_completion); 1554 init_completion(&master->xfer_completion);
1555 if (!master->max_dma_len)
1556 master->max_dma_len = INT_MAX;
1506 1557
1507 /* register the device, then userspace will see it. 1558 /* register the device, then userspace will see it.
1508 * registration fails if the bus ID is in use. 1559 * registration fails if the bus ID is in use.