dmaengine: plx-dma: Introduce PLX DMA engine PCI driver skeleton

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>
This commit is contained in:
Logan Gunthorpe 2020-01-03 14:20:19 -07:00 committed by Vinod Koul
parent 02939cd167
commit 905ca51e63
4 changed files with 165 additions and 0 deletions

View File

@ -13139,6 +13139,11 @@ S: Maintained
F: drivers/iio/chemical/pms7003.c F: drivers/iio/chemical/pms7003.c
F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml 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 PMBUS HARDWARE MONITORING DRIVERS
M: Guenter Roeck <linux@roeck-us.net> M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org L: linux-hwmon@vger.kernel.org

View File

@ -497,6 +497,15 @@ config PXA_DMA
16 to 32 channels for peripheral to memory or memory to memory 16 to 32 channels for peripheral to memory or memory to memory
transfers. 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 config SIRF_DMA
tristate "CSR SiRFprimaII/SiRFmarco DMA support" tristate "CSR SiRFprimaII/SiRFmarco DMA support"
depends on ARCH_SIRF depends on ARCH_SIRF

View File

@ -59,6 +59,7 @@ obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
obj-$(CONFIG_OWL_DMA) += owl-dma.o obj-$(CONFIG_OWL_DMA) += owl-dma.o
obj-$(CONFIG_PCH_DMA) += pch_dma.o obj-$(CONFIG_PCH_DMA) += pch_dma.o
obj-$(CONFIG_PL330_DMA) += pl330.o obj-$(CONFIG_PL330_DMA) += pl330.o
obj-$(CONFIG_PLX_DMA) += plx_dma.o
obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
obj-$(CONFIG_PXA_DMA) += pxa_dma.o obj-$(CONFIG_PXA_DMA) += pxa_dma.o
obj-$(CONFIG_RENESAS_DMA) += sh/ obj-$(CONFIG_RENESAS_DMA) += sh/

150
drivers/dma/plx_dma.c Normal file
View File

@ -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);