]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
dmaengine: plx-dma: Introduce PLX DMA engine PCI driver skeleton
authorLogan Gunthorpe <logang@deltatee.com>
Fri, 3 Jan 2020 21:20:19 +0000 (14:20 -0700)
committerVinod Koul <vkoul@kernel.org>
Wed, 15 Jan 2020 14:10:51 +0000 (19:40 +0530)
Some PLX Switches can expose DMA engines via extra PCI functions
on the upstream port. Each function will have one DMA channel.

This patch is just the core PCI driver skeleton and dma
engine registration.

Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Link: https://lore.kernel.org/r/20200103212021.2881-2-logang@deltatee.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
MAINTAINERS
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/plx_dma.c [new file with mode: 0644]

index bd5847e802defb11887f45dd17412e1e98d054e8..76713226f2562f5e06e9821c51c92738220639c5 100644 (file)
@@ -13139,6 +13139,11 @@ S:     Maintained
 F:     drivers/iio/chemical/pms7003.c
 F:     Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
 
+PLX DMA DRIVER
+M:     Logan Gunthorpe <logang@deltatee.com>
+S:     Maintained
+F:     drivers/dma/plx_dma.c
+
 PMBUS HARDWARE MONITORING DRIVERS
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
index 6fa1eba9d4778775c57bdbef8f3c0bbb57b79bfc..312a6cc36c78694ba1d6b77bb9aee00e7524bfc9 100644 (file)
@@ -497,6 +497,15 @@ config PXA_DMA
          16 to 32 channels for peripheral to memory or memory to memory
          transfers.
 
+config PLX_DMA
+       tristate "PLX ExpressLane PEX Switch DMA Engine Support"
+       depends on PCI
+       select DMA_ENGINE
+       help
+         Some PLX ExpressLane PCI Switches support additional DMA engines.
+         These are exposed via extra functions on the switch's
+         upstream port. Each function exposes one DMA channel.
+
 config SIRF_DMA
        tristate "CSR SiRFprimaII/SiRFmarco DMA support"
        depends on ARCH_SIRF
index 42d7e2fc64faf8a4ac7100f78e060a598eb11eec..a150d1d792fd811b8ffc798581b6fcfd2bb9ab67 100644 (file)
@@ -59,6 +59,7 @@ obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
 obj-$(CONFIG_OWL_DMA) += owl-dma.o
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
 obj-$(CONFIG_PL330_DMA) += pl330.o
+obj-$(CONFIG_PLX_DMA) += plx_dma.o
 obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
 obj-$(CONFIG_PXA_DMA) += pxa_dma.o
 obj-$(CONFIG_RENESAS_DMA) += sh/
diff --git a/drivers/dma/plx_dma.c b/drivers/dma/plx_dma.c
new file mode 100644 (file)
index 0000000..e002cbb
--- /dev/null
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microsemi Switchtec(tm) PCIe Management Driver
+ * Copyright (c) 2019, Logan Gunthorpe <logang@deltatee.com>
+ * Copyright (c) 2019, GigaIO Networks, Inc
+ */
+
+#include "dmaengine.h"
+
+#include <linux/dmaengine.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+MODULE_DESCRIPTION("PLX ExpressLane PEX PCI Switch DMA Engine");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Logan Gunthorpe");
+
+struct plx_dma_dev {
+       struct dma_device dma_dev;
+       struct dma_chan dma_chan;
+       void __iomem *bar;
+};
+
+static void plx_dma_release(struct dma_device *dma_dev)
+{
+       struct plx_dma_dev *plxdev =
+               container_of(dma_dev, struct plx_dma_dev, dma_dev);
+
+       put_device(dma_dev->dev);
+       kfree(plxdev);
+}
+
+static int plx_dma_create(struct pci_dev *pdev)
+{
+       struct plx_dma_dev *plxdev;
+       struct dma_device *dma;
+       struct dma_chan *chan;
+       int rc;
+
+       plxdev = kzalloc(sizeof(*plxdev), GFP_KERNEL);
+       if (!plxdev)
+               return -ENOMEM;
+
+       plxdev->bar = pcim_iomap_table(pdev)[0];
+
+       dma = &plxdev->dma_dev;
+       dma->chancnt = 1;
+       INIT_LIST_HEAD(&dma->channels);
+       dma->copy_align = DMAENGINE_ALIGN_1_BYTE;
+       dma->dev = get_device(&pdev->dev);
+
+       dma->device_release = plx_dma_release;
+
+       chan = &plxdev->dma_chan;
+       chan->device = dma;
+       dma_cookie_init(chan);
+       list_add_tail(&chan->device_node, &dma->channels);
+
+       rc = dma_async_device_register(dma);
+       if (rc) {
+               pci_err(pdev, "Failed to register dma device: %d\n", rc);
+               free_irq(pci_irq_vector(pdev, 0),  plxdev);
+               kfree(plxdev);
+               return rc;
+       }
+
+       pci_set_drvdata(pdev, plxdev);
+
+       return 0;
+}
+
+static int plx_dma_probe(struct pci_dev *pdev,
+                        const struct pci_device_id *id)
+{
+       int rc;
+
+       rc = pcim_enable_device(pdev);
+       if (rc)
+               return rc;
+
+       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(48));
+       if (rc)
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+
+       rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(48));
+       if (rc)
+               rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+
+       rc = pcim_iomap_regions(pdev, 1, KBUILD_MODNAME);
+       if (rc)
+               return rc;
+
+       rc = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+       if (rc <= 0)
+               return rc;
+
+       pci_set_master(pdev);
+
+       rc = plx_dma_create(pdev);
+       if (rc)
+               goto err_free_irq_vectors;
+
+       pci_info(pdev, "PLX DMA Channel Registered\n");
+
+       return 0;
+
+err_free_irq_vectors:
+       pci_free_irq_vectors(pdev);
+       return rc;
+}
+
+static void plx_dma_remove(struct pci_dev *pdev)
+{
+       struct plx_dma_dev *plxdev = pci_get_drvdata(pdev);
+
+       free_irq(pci_irq_vector(pdev, 0),  plxdev);
+
+       plxdev->bar = NULL;
+       dma_async_device_unregister(&plxdev->dma_dev);
+
+       pci_free_irq_vectors(pdev);
+}
+
+static const struct pci_device_id plx_dma_pci_tbl[] = {
+       {
+               .vendor         = PCI_VENDOR_ID_PLX,
+               .device         = 0x87D0,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .class          = PCI_CLASS_SYSTEM_OTHER << 8,
+               .class_mask     = 0xFFFFFFFF,
+       },
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, plx_dma_pci_tbl);
+
+static struct pci_driver plx_dma_pci_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = plx_dma_pci_tbl,
+       .probe          = plx_dma_probe,
+       .remove         = plx_dma_remove,
+};
+module_pci_driver(plx_dma_pci_driver);