linux/drivers/dma/amd/ptdma/ptdma-pci.c
Basavaraj Natikar e01ee7c660 dmaengine: Move AMD PTDMA driver to amd directory
PTDMA driver is the AMD DMA driver, and newer AMD platforms support newer
DMA engines. Hence, move the current drivers to the AMD directory. This
would also mean that future driver submissions to the AMD DMA driver will
also land in the AMD-specific directory.

Reviewed-by: Raju Rangoju <Raju.Rangoju@amd.com>
Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
Link: https://lore.kernel.org/r/20241025095931.726018-2-Basavaraj.Natikar@amd.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2024-12-02 22:55:27 +05:30

243 lines
4.6 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Passthru DMA device driver
* -- Based on the CCP driver
*
* Copyright (C) 2016,2021 Advanced Micro Devices, Inc.
*
* Author: Sanjay R Mehta <sanju.mehta@amd.com>
* Author: Tom Lendacky <thomas.lendacky@amd.com>
* Author: Gary R Hook <gary.hook@amd.com>
*/
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/pci_ids.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include "ptdma.h"
struct pt_msix {
int msix_count;
struct msix_entry msix_entry;
};
/*
* pt_alloc_struct - allocate and initialize the pt_device struct
*
* @dev: device struct of the PTDMA
*/
static struct pt_device *pt_alloc_struct(struct device *dev)
{
struct pt_device *pt;
pt = devm_kzalloc(dev, sizeof(*pt), GFP_KERNEL);
if (!pt)
return NULL;
pt->dev = dev;
INIT_LIST_HEAD(&pt->cmd);
return pt;
}
static int pt_get_msix_irqs(struct pt_device *pt)
{
struct pt_msix *pt_msix = pt->pt_msix;
struct device *dev = pt->dev;
struct pci_dev *pdev = to_pci_dev(dev);
int ret;
pt_msix->msix_entry.entry = 0;
ret = pci_enable_msix_range(pdev, &pt_msix->msix_entry, 1, 1);
if (ret < 0)
return ret;
pt_msix->msix_count = ret;
pt->pt_irq = pt_msix->msix_entry.vector;
return 0;
}
static int pt_get_msi_irq(struct pt_device *pt)
{
struct device *dev = pt->dev;
struct pci_dev *pdev = to_pci_dev(dev);
int ret;
ret = pci_enable_msi(pdev);
if (ret)
return ret;
pt->pt_irq = pdev->irq;
return 0;
}
static int pt_get_irqs(struct pt_device *pt)
{
struct device *dev = pt->dev;
int ret;
ret = pt_get_msix_irqs(pt);
if (!ret)
return 0;
/* Couldn't get MSI-X vectors, try MSI */
dev_err(dev, "could not enable MSI-X (%d), trying MSI\n", ret);
ret = pt_get_msi_irq(pt);
if (!ret)
return 0;
/* Couldn't get MSI interrupt */
dev_err(dev, "could not enable MSI (%d)\n", ret);
return ret;
}
static void pt_free_irqs(struct pt_device *pt)
{
struct pt_msix *pt_msix = pt->pt_msix;
struct device *dev = pt->dev;
struct pci_dev *pdev = to_pci_dev(dev);
if (pt_msix->msix_count)
pci_disable_msix(pdev);
else if (pt->pt_irq)
pci_disable_msi(pdev);
pt->pt_irq = 0;
}
static int pt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pt_device *pt;
struct pt_msix *pt_msix;
struct device *dev = &pdev->dev;
void __iomem * const *iomap_table;
int bar_mask;
int ret = -ENOMEM;
pt = pt_alloc_struct(dev);
if (!pt)
goto e_err;
pt_msix = devm_kzalloc(dev, sizeof(*pt_msix), GFP_KERNEL);
if (!pt_msix)
goto e_err;
pt->pt_msix = pt_msix;
pt->dev_vdata = (struct pt_dev_vdata *)id->driver_data;
if (!pt->dev_vdata) {
ret = -ENODEV;
dev_err(dev, "missing driver data\n");
goto e_err;
}
ret = pcim_enable_device(pdev);
if (ret) {
dev_err(dev, "pcim_enable_device failed (%d)\n", ret);
goto e_err;
}
bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
ret = pcim_iomap_regions(pdev, bar_mask, "ptdma");
if (ret) {
dev_err(dev, "pcim_iomap_regions failed (%d)\n", ret);
goto e_err;
}
iomap_table = pcim_iomap_table(pdev);
if (!iomap_table) {
dev_err(dev, "pcim_iomap_table failed\n");
ret = -ENOMEM;
goto e_err;
}
pt->io_regs = iomap_table[pt->dev_vdata->bar];
if (!pt->io_regs) {
dev_err(dev, "ioremap failed\n");
ret = -ENOMEM;
goto e_err;
}
ret = pt_get_irqs(pt);
if (ret)
goto e_err;
pci_set_master(pdev);
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
if (ret) {
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n",
ret);
goto e_err;
}
}
dev_set_drvdata(dev, pt);
if (pt->dev_vdata)
ret = pt_core_init(pt);
if (ret)
goto e_err;
return 0;
e_err:
dev_err(dev, "initialization failed ret = %d\n", ret);
return ret;
}
static void pt_pci_remove(struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
struct pt_device *pt = dev_get_drvdata(dev);
if (!pt)
return;
if (pt->dev_vdata)
pt_core_destroy(pt);
pt_free_irqs(pt);
}
static const struct pt_dev_vdata dev_vdata[] = {
{
.bar = 2,
},
};
static const struct pci_device_id pt_pci_table[] = {
{ PCI_VDEVICE(AMD, 0x1498), (kernel_ulong_t)&dev_vdata[0] },
/* Last entry must be zero */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, pt_pci_table);
static struct pci_driver pt_pci_driver = {
.name = "ptdma",
.id_table = pt_pci_table,
.probe = pt_pci_probe,
.remove = pt_pci_remove,
};
module_pci_driver(pt_pci_driver);
MODULE_AUTHOR("Sanjay R Mehta <sanju.mehta@amd.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AMD PassThru DMA driver");