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

Configure Feed

Select the types of activity you want to include in your feed.

dmaengine: switchtec-dma: Introduce Switchtec DMA engine skeleton

Some Switchtec Switches can expose DMA engines via extra PCI functions
on the upstream ports. At most one such function can be supported on
each upstream port. Each function can have one or more DMA channels.

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

Signed-off-by: Kelvin Cao <kelvin.cao@microchip.com>
Co-developed-by: George Ge <george.ge@microchip.com>
Signed-off-by: George Ge <george.ge@microchip.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Link: https://patch.msgid.link/20260302210419.3656-2-logang@deltatee.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Kelvin Cao and committed by
Vinod Koul
d9587042 f1d201e7

+226
+7
MAINTAINERS
··· 25524 25524 F: include/net/switchdev.h 25525 25525 F: net/switchdev/ 25526 25526 25527 + SWITCHTEC DMA DRIVER 25528 + M: Kelvin Cao <kelvin.cao@microchip.com> 25529 + M: Logan Gunthorpe <logang@deltatee.com> 25530 + L: dmaengine@vger.kernel.org 25531 + S: Maintained 25532 + F: drivers/dma/switchtec_dma.c 25533 + 25527 25534 SY8106A REGULATOR DRIVER 25528 25535 M: Icenowy Zheng <icenowy@aosc.io> 25529 25536 S: Maintained
+9
drivers/dma/Kconfig
··· 610 610 help 611 611 Enable support for the on-chip DMA controller on Spreadtrum platform. 612 612 613 + config SWITCHTEC_DMA 614 + tristate "Switchtec PSX/PFX Switch DMA Engine Support" 615 + depends on PCI 616 + select DMA_ENGINE 617 + help 618 + Some Switchtec PSX/PFX PCIe Switches support additional DMA engines. 619 + These are exposed via an extra function on the switch's upstream 620 + port. 621 + 613 622 config TXX9_DMAC 614 623 tristate "Toshiba TXx9 SoC DMA support" 615 624 depends on MACH_TX49XX
+1
drivers/dma/Makefile
··· 74 74 obj-$(CONFIG_SOPHGO_CV1800B_DMAMUX) += cv1800b-dmamux.o 75 75 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o 76 76 obj-$(CONFIG_SPRD_DMA) += sprd-dma.o 77 + obj-$(CONFIG_SWITCHTEC_DMA) += switchtec_dma.o 77 78 obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o 78 79 obj-$(CONFIG_TEGRA186_GPC_DMA) += tegra186-gpc-dma.o 79 80 obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
+209
drivers/dma/switchtec_dma.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Microchip Switchtec(tm) DMA Controller Driver 4 + * Copyright (c) 2025, Kelvin Cao <kelvin.cao@microchip.com> 5 + * Copyright (c) 2025, Microchip Corporation 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/circ_buf.h> 10 + #include <linux/dmaengine.h> 11 + #include <linux/module.h> 12 + #include <linux/pci.h> 13 + #include <linux/delay.h> 14 + #include <linux/iopoll.h> 15 + 16 + #include "dmaengine.h" 17 + 18 + MODULE_DESCRIPTION("Switchtec PCIe Switch DMA Engine"); 19 + MODULE_LICENSE("GPL"); 20 + MODULE_AUTHOR("Kelvin Cao"); 21 + 22 + struct switchtec_dma_dev { 23 + struct dma_device dma_dev; 24 + struct pci_dev __rcu *pdev; 25 + void __iomem *bar; 26 + }; 27 + 28 + static void switchtec_dma_release(struct dma_device *dma_dev) 29 + { 30 + struct switchtec_dma_dev *swdma_dev = 31 + container_of(dma_dev, struct switchtec_dma_dev, dma_dev); 32 + 33 + put_device(dma_dev->dev); 34 + kfree(swdma_dev); 35 + } 36 + 37 + static int switchtec_dma_create(struct pci_dev *pdev) 38 + { 39 + struct switchtec_dma_dev *swdma_dev; 40 + struct dma_device *dma; 41 + struct dma_chan *chan; 42 + int nr_vecs, rc; 43 + 44 + /* 45 + * Create the switchtec dma device 46 + */ 47 + swdma_dev = kzalloc_obj(*swdma_dev, GFP_KERNEL); 48 + if (!swdma_dev) 49 + return -ENOMEM; 50 + 51 + swdma_dev->bar = ioremap(pci_resource_start(pdev, 0), 52 + pci_resource_len(pdev, 0)); 53 + 54 + RCU_INIT_POINTER(swdma_dev->pdev, pdev); 55 + 56 + nr_vecs = pci_msix_vec_count(pdev); 57 + rc = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX); 58 + if (rc < 0) 59 + goto err_exit; 60 + 61 + dma = &swdma_dev->dma_dev; 62 + dma->copy_align = DMAENGINE_ALIGN_8_BYTES; 63 + dma->dev = get_device(&pdev->dev); 64 + 65 + dma->device_release = switchtec_dma_release; 66 + 67 + rc = dma_async_device_register(dma); 68 + if (rc) { 69 + pci_err(pdev, "Failed to register dma device: %d\n", rc); 70 + goto err_exit; 71 + } 72 + 73 + list_for_each_entry(chan, &dma->channels, device_node) 74 + pci_dbg(pdev, "%s\n", dma_chan_name(chan)); 75 + 76 + pci_set_drvdata(pdev, swdma_dev); 77 + 78 + return 0; 79 + 80 + err_exit: 81 + iounmap(swdma_dev->bar); 82 + kfree(swdma_dev); 83 + return rc; 84 + } 85 + 86 + static int switchtec_dma_probe(struct pci_dev *pdev, 87 + const struct pci_device_id *id) 88 + { 89 + int rc; 90 + 91 + rc = pci_enable_device(pdev); 92 + if (rc) 93 + return rc; 94 + 95 + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 96 + 97 + rc = pci_request_mem_regions(pdev, KBUILD_MODNAME); 98 + if (rc) 99 + goto err_disable; 100 + 101 + pci_set_master(pdev); 102 + 103 + rc = switchtec_dma_create(pdev); 104 + if (rc) 105 + goto err_free; 106 + 107 + return 0; 108 + 109 + err_free: 110 + pci_free_irq_vectors(pdev); 111 + pci_release_mem_regions(pdev); 112 + 113 + err_disable: 114 + pci_disable_device(pdev); 115 + 116 + return rc; 117 + } 118 + 119 + static void switchtec_dma_remove(struct pci_dev *pdev) 120 + { 121 + struct switchtec_dma_dev *swdma_dev = pci_get_drvdata(pdev); 122 + 123 + rcu_assign_pointer(swdma_dev->pdev, NULL); 124 + synchronize_rcu(); 125 + 126 + pci_free_irq_vectors(pdev); 127 + 128 + dma_async_device_unregister(&swdma_dev->dma_dev); 129 + 130 + iounmap(swdma_dev->bar); 131 + pci_release_mem_regions(pdev); 132 + pci_disable_device(pdev); 133 + } 134 + 135 + /* 136 + * Also use the class code to identify the devices, as some of the 137 + * device IDs are also used for other devices with other classes by 138 + * Microsemi. 139 + */ 140 + #define SW_ID(vendor_id, device_id) \ 141 + { \ 142 + .vendor = vendor_id, \ 143 + .device = device_id, \ 144 + .subvendor = PCI_ANY_ID, \ 145 + .subdevice = PCI_ANY_ID, \ 146 + .class = PCI_CLASS_SYSTEM_OTHER << 8, \ 147 + .class_mask = 0xffffffff, \ 148 + } 149 + 150 + static const struct pci_device_id switchtec_dma_pci_tbl[] = { 151 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4000), /* PFX 100XG4 */ 152 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4084), /* PFX 84XG4 */ 153 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4068), /* PFX 68XG4 */ 154 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4052), /* PFX 52XG4 */ 155 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4036), /* PFX 36XG4 */ 156 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4028), /* PFX 28XG4 */ 157 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4100), /* PSX 100XG4 */ 158 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4184), /* PSX 84XG4 */ 159 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4168), /* PSX 68XG4 */ 160 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4152), /* PSX 52XG4 */ 161 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4136), /* PSX 36XG4 */ 162 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4128), /* PSX 28XG4 */ 163 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4352), /* PFXA 52XG4 */ 164 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4336), /* PFXA 36XG4 */ 165 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4328), /* PFXA 28XG4 */ 166 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4452), /* PSXA 52XG4 */ 167 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4436), /* PSXA 36XG4 */ 168 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x4428), /* PSXA 28XG4 */ 169 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5000), /* PFX 100XG5 */ 170 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5084), /* PFX 84XG5 */ 171 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5068), /* PFX 68XG5 */ 172 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5052), /* PFX 52XG5 */ 173 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5036), /* PFX 36XG5 */ 174 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5028), /* PFX 28XG5 */ 175 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5100), /* PSX 100XG5 */ 176 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5184), /* PSX 84XG5 */ 177 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5168), /* PSX 68XG5 */ 178 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5152), /* PSX 52XG5 */ 179 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5136), /* PSX 36XG5 */ 180 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5128), /* PSX 28XG5 */ 181 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5300), /* PFXA 100XG5 */ 182 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5384), /* PFXA 84XG5 */ 183 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5368), /* PFXA 68XG5 */ 184 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5352), /* PFXA 52XG5 */ 185 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5336), /* PFXA 36XG5 */ 186 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5328), /* PFXA 28XG5 */ 187 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5400), /* PSXA 100XG5 */ 188 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5484), /* PSXA 84XG5 */ 189 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5468), /* PSXA 68XG5 */ 190 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5452), /* PSXA 52XG5 */ 191 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5436), /* PSXA 36XG5 */ 192 + SW_ID(PCI_VENDOR_ID_MICROSEMI, 0x5428), /* PSXA 28XG5 */ 193 + SW_ID(PCI_VENDOR_ID_EFAR, 0x1001), /* PCI1001 16XG4 */ 194 + SW_ID(PCI_VENDOR_ID_EFAR, 0x1002), /* PCI1002 16XG4 */ 195 + SW_ID(PCI_VENDOR_ID_EFAR, 0x1003), /* PCI1003 16XG4 */ 196 + SW_ID(PCI_VENDOR_ID_EFAR, 0x1004), /* PCI1004 16XG4 */ 197 + SW_ID(PCI_VENDOR_ID_EFAR, 0x1005), /* PCI1005 16XG4 */ 198 + SW_ID(PCI_VENDOR_ID_EFAR, 0x1006), /* PCI1006 16XG4 */ 199 + {0} 200 + }; 201 + MODULE_DEVICE_TABLE(pci, switchtec_dma_pci_tbl); 202 + 203 + static struct pci_driver switchtec_dma_pci_driver = { 204 + .name = KBUILD_MODNAME, 205 + .id_table = switchtec_dma_pci_tbl, 206 + .probe = switchtec_dma_probe, 207 + .remove = switchtec_dma_remove, 208 + }; 209 + module_pci_driver(switchtec_dma_pci_driver);