1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * AMD AE4DMA driver
4 *
5 * Copyright (c) 2024, Advanced Micro Devices, Inc.
6 * All Rights Reserved.
7 *
8 * Author: Basavaraj Natikar <[email protected]>
9 */
10
11 #include "ae4dma.h"
12
ae4_get_irqs(struct ae4_device * ae4)13 static int ae4_get_irqs(struct ae4_device *ae4)
14 {
15 struct ae4_msix *ae4_msix = ae4->ae4_msix;
16 struct pt_device *pt = &ae4->pt;
17 struct device *dev = pt->dev;
18 struct pci_dev *pdev;
19 int i, v, ret;
20
21 pdev = to_pci_dev(dev);
22
23 for (v = 0; v < ARRAY_SIZE(ae4_msix->msix_entry); v++)
24 ae4_msix->msix_entry[v].entry = v;
25
26 ret = pci_alloc_irq_vectors(pdev, v, v, PCI_IRQ_MSIX);
27 if (ret != v) {
28 if (ret > 0)
29 pci_free_irq_vectors(pdev);
30
31 dev_err(dev, "could not enable MSI-X (%d), trying MSI\n", ret);
32 ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
33 if (ret < 0) {
34 dev_err(dev, "could not enable MSI (%d)\n", ret);
35 return ret;
36 }
37
38 ret = pci_irq_vector(pdev, 0);
39 if (ret < 0) {
40 pci_free_irq_vectors(pdev);
41 return ret;
42 }
43
44 for (i = 0; i < MAX_AE4_HW_QUEUES; i++)
45 ae4->ae4_irq[i] = ret;
46
47 } else {
48 ae4_msix->msix_count = ret;
49 for (i = 0; i < ae4_msix->msix_count; i++)
50 ae4->ae4_irq[i] = pci_irq_vector(pdev, i);
51 }
52
53 return ret;
54 }
55
ae4_free_irqs(struct ae4_device * ae4)56 static void ae4_free_irqs(struct ae4_device *ae4)
57 {
58 struct ae4_msix *ae4_msix = ae4->ae4_msix;
59 struct pt_device *pt = &ae4->pt;
60 struct device *dev = pt->dev;
61 struct pci_dev *pdev;
62
63 pdev = to_pci_dev(dev);
64
65 if (ae4_msix && (ae4_msix->msix_count || ae4->ae4_irq[MAX_AE4_HW_QUEUES - 1]))
66 pci_free_irq_vectors(pdev);
67 }
68
ae4_deinit(struct ae4_device * ae4)69 static void ae4_deinit(struct ae4_device *ae4)
70 {
71 ae4_free_irqs(ae4);
72 }
73
ae4_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)74 static int ae4_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
75 {
76 struct device *dev = &pdev->dev;
77 struct ae4_device *ae4;
78 struct pt_device *pt;
79 int bar_mask;
80 int ret = 0;
81
82 ae4 = devm_kzalloc(dev, sizeof(*ae4), GFP_KERNEL);
83 if (!ae4)
84 return -ENOMEM;
85
86 ae4->ae4_msix = devm_kzalloc(dev, sizeof(struct ae4_msix), GFP_KERNEL);
87 if (!ae4->ae4_msix)
88 return -ENOMEM;
89
90 ret = pcim_enable_device(pdev);
91 if (ret)
92 goto ae4_error;
93
94 bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
95 ret = pcim_iomap_regions(pdev, bar_mask, "ae4dma");
96 if (ret)
97 goto ae4_error;
98
99 pt = &ae4->pt;
100 pt->dev = dev;
101 pt->ver = AE4_DMA_VERSION;
102
103 pt->io_regs = pcim_iomap_table(pdev)[0];
104 if (!pt->io_regs) {
105 ret = -ENOMEM;
106 goto ae4_error;
107 }
108
109 ret = ae4_get_irqs(ae4);
110 if (ret < 0)
111 goto ae4_error;
112
113 pci_set_master(pdev);
114
115 dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
116
117 dev_set_drvdata(dev, ae4);
118
119 ret = ae4_core_init(ae4);
120 if (ret)
121 goto ae4_error;
122
123 return 0;
124
125 ae4_error:
126 ae4_deinit(ae4);
127
128 return ret;
129 }
130
ae4_pci_remove(struct pci_dev * pdev)131 static void ae4_pci_remove(struct pci_dev *pdev)
132 {
133 struct ae4_device *ae4 = dev_get_drvdata(&pdev->dev);
134
135 ae4_destroy_work(ae4);
136 ae4_deinit(ae4);
137 }
138
139 static const struct pci_device_id ae4_pci_table[] = {
140 { PCI_VDEVICE(AMD, 0x14C8), },
141 { PCI_VDEVICE(AMD, 0x14DC), },
142 { PCI_VDEVICE(AMD, 0x149B), },
143 /* Last entry must be zero */
144 { 0, }
145 };
146 MODULE_DEVICE_TABLE(pci, ae4_pci_table);
147
148 static struct pci_driver ae4_pci_driver = {
149 .name = "ae4dma",
150 .id_table = ae4_pci_table,
151 .probe = ae4_pci_probe,
152 .remove = ae4_pci_remove,
153 };
154
155 module_pci_driver(ae4_pci_driver);
156
157 MODULE_LICENSE("GPL");
158 MODULE_DESCRIPTION("AMD AE4DMA driver");
159