.. | .. |
---|
31 | 31 | struct dfl_fpga_cdev *cdev; /* container device */ |
---|
32 | 32 | }; |
---|
33 | 33 | |
---|
34 | | -static void __iomem *cci_pci_ioremap_bar(struct pci_dev *pcidev, int bar) |
---|
| 34 | +static void __iomem *cci_pci_ioremap_bar0(struct pci_dev *pcidev) |
---|
35 | 35 | { |
---|
36 | | - if (pcim_iomap_regions(pcidev, BIT(bar), DRV_NAME)) |
---|
| 36 | + if (pcim_iomap_regions(pcidev, BIT(0), DRV_NAME)) |
---|
37 | 37 | return NULL; |
---|
38 | 38 | |
---|
39 | | - return pcim_iomap_table(pcidev)[bar]; |
---|
| 39 | + return pcim_iomap_table(pcidev)[0]; |
---|
| 40 | +} |
---|
| 41 | + |
---|
| 42 | +static int cci_pci_alloc_irq(struct pci_dev *pcidev) |
---|
| 43 | +{ |
---|
| 44 | + int ret, nvec = pci_msix_vec_count(pcidev); |
---|
| 45 | + |
---|
| 46 | + if (nvec <= 0) { |
---|
| 47 | + dev_dbg(&pcidev->dev, "fpga interrupt not supported\n"); |
---|
| 48 | + return 0; |
---|
| 49 | + } |
---|
| 50 | + |
---|
| 51 | + ret = pci_alloc_irq_vectors(pcidev, nvec, nvec, PCI_IRQ_MSIX); |
---|
| 52 | + if (ret < 0) |
---|
| 53 | + return ret; |
---|
| 54 | + |
---|
| 55 | + return nvec; |
---|
| 56 | +} |
---|
| 57 | + |
---|
| 58 | +static void cci_pci_free_irq(struct pci_dev *pcidev) |
---|
| 59 | +{ |
---|
| 60 | + pci_free_irq_vectors(pcidev); |
---|
40 | 61 | } |
---|
41 | 62 | |
---|
42 | 63 | /* PCI Device ID */ |
---|
43 | | -#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD |
---|
44 | | -#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 |
---|
45 | | -#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 |
---|
| 64 | +#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD |
---|
| 65 | +#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 |
---|
| 66 | +#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 |
---|
| 67 | +#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 |
---|
| 68 | +#define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B |
---|
46 | 69 | /* VF Device */ |
---|
47 | | -#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF |
---|
48 | | -#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 |
---|
49 | | -#define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 |
---|
| 70 | +#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF |
---|
| 71 | +#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 |
---|
| 72 | +#define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 |
---|
| 73 | +#define PCIE_DEVICE_ID_INTEL_PAC_D5005_VF 0x0B2C |
---|
50 | 74 | |
---|
51 | 75 | static struct pci_device_id cci_pcie_id_tbl[] = { |
---|
52 | 76 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X),}, |
---|
.. | .. |
---|
55 | 79 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X),}, |
---|
56 | 80 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),}, |
---|
57 | 81 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),}, |
---|
| 82 | + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),}, |
---|
| 83 | + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),}, |
---|
| 84 | + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, |
---|
58 | 85 | {0,} |
---|
59 | 86 | }; |
---|
60 | 87 | MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); |
---|
.. | .. |
---|
78 | 105 | |
---|
79 | 106 | /* remove all children feature devices */ |
---|
80 | 107 | dfl_fpga_feature_devs_remove(drvdata->cdev); |
---|
| 108 | + cci_pci_free_irq(pcidev); |
---|
| 109 | +} |
---|
| 110 | + |
---|
| 111 | +static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec) |
---|
| 112 | +{ |
---|
| 113 | + unsigned int i; |
---|
| 114 | + int *table; |
---|
| 115 | + |
---|
| 116 | + table = kcalloc(nvec, sizeof(int), GFP_KERNEL); |
---|
| 117 | + if (!table) |
---|
| 118 | + return table; |
---|
| 119 | + |
---|
| 120 | + for (i = 0; i < nvec; i++) |
---|
| 121 | + table[i] = pci_irq_vector(pcidev, i); |
---|
| 122 | + |
---|
| 123 | + return table; |
---|
81 | 124 | } |
---|
82 | 125 | |
---|
83 | 126 | /* enumerate feature devices under pci device */ |
---|
84 | 127 | static int cci_enumerate_feature_devs(struct pci_dev *pcidev) |
---|
85 | 128 | { |
---|
86 | 129 | struct cci_drvdata *drvdata = pci_get_drvdata(pcidev); |
---|
| 130 | + int port_num, bar, i, nvec, ret = 0; |
---|
87 | 131 | struct dfl_fpga_enum_info *info; |
---|
88 | 132 | struct dfl_fpga_cdev *cdev; |
---|
89 | 133 | resource_size_t start, len; |
---|
90 | | - int port_num, bar, i, ret = 0; |
---|
91 | 134 | void __iomem *base; |
---|
| 135 | + int *irq_table; |
---|
92 | 136 | u32 offset; |
---|
93 | 137 | u64 v; |
---|
94 | 138 | |
---|
.. | .. |
---|
97 | 141 | if (!info) |
---|
98 | 142 | return -ENOMEM; |
---|
99 | 143 | |
---|
100 | | - /* start to find Device Feature List from Bar 0 */ |
---|
101 | | - base = cci_pci_ioremap_bar(pcidev, 0); |
---|
| 144 | + /* add irq info for enumeration if the device support irq */ |
---|
| 145 | + nvec = cci_pci_alloc_irq(pcidev); |
---|
| 146 | + if (nvec < 0) { |
---|
| 147 | + dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec); |
---|
| 148 | + ret = nvec; |
---|
| 149 | + goto enum_info_free_exit; |
---|
| 150 | + } else if (nvec) { |
---|
| 151 | + irq_table = cci_pci_create_irq_table(pcidev, nvec); |
---|
| 152 | + if (!irq_table) { |
---|
| 153 | + ret = -ENOMEM; |
---|
| 154 | + goto irq_free_exit; |
---|
| 155 | + } |
---|
| 156 | + |
---|
| 157 | + ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table); |
---|
| 158 | + kfree(irq_table); |
---|
| 159 | + if (ret) |
---|
| 160 | + goto irq_free_exit; |
---|
| 161 | + } |
---|
| 162 | + |
---|
| 163 | + /* start to find Device Feature List in Bar 0 */ |
---|
| 164 | + base = cci_pci_ioremap_bar0(pcidev); |
---|
102 | 165 | if (!base) { |
---|
103 | 166 | ret = -ENOMEM; |
---|
104 | | - goto enum_info_free_exit; |
---|
| 167 | + goto irq_free_exit; |
---|
105 | 168 | } |
---|
106 | 169 | |
---|
107 | 170 | /* |
---|
.. | .. |
---|
113 | 176 | start = pci_resource_start(pcidev, 0); |
---|
114 | 177 | len = pci_resource_len(pcidev, 0); |
---|
115 | 178 | |
---|
116 | | - dfl_fpga_enum_info_add_dfl(info, start, len, base); |
---|
| 179 | + dfl_fpga_enum_info_add_dfl(info, start, len); |
---|
117 | 180 | |
---|
118 | 181 | /* |
---|
119 | 182 | * find more Device Feature Lists (e.g. Ports) per information |
---|
.. | .. |
---|
137 | 200 | */ |
---|
138 | 201 | bar = FIELD_GET(FME_PORT_OFST_BAR_ID, v); |
---|
139 | 202 | offset = FIELD_GET(FME_PORT_OFST_DFH_OFST, v); |
---|
140 | | - base = cci_pci_ioremap_bar(pcidev, bar); |
---|
141 | | - if (!base) |
---|
142 | | - continue; |
---|
143 | | - |
---|
144 | 203 | start = pci_resource_start(pcidev, bar) + offset; |
---|
145 | 204 | len = pci_resource_len(pcidev, bar) - offset; |
---|
146 | 205 | |
---|
147 | | - dfl_fpga_enum_info_add_dfl(info, start, len, |
---|
148 | | - base + offset); |
---|
| 206 | + dfl_fpga_enum_info_add_dfl(info, start, len); |
---|
149 | 207 | } |
---|
150 | 208 | } else if (dfl_feature_is_port(base)) { |
---|
151 | 209 | start = pci_resource_start(pcidev, 0); |
---|
152 | 210 | len = pci_resource_len(pcidev, 0); |
---|
153 | 211 | |
---|
154 | | - dfl_fpga_enum_info_add_dfl(info, start, len, base); |
---|
| 212 | + dfl_fpga_enum_info_add_dfl(info, start, len); |
---|
155 | 213 | } else { |
---|
156 | 214 | ret = -ENODEV; |
---|
157 | | - goto enum_info_free_exit; |
---|
| 215 | + goto irq_free_exit; |
---|
158 | 216 | } |
---|
| 217 | + |
---|
| 218 | + /* release I/O mappings for next step enumeration */ |
---|
| 219 | + pcim_iounmap_regions(pcidev, BIT(0)); |
---|
159 | 220 | |
---|
160 | 221 | /* start enumeration with prepared enumeration information */ |
---|
161 | 222 | cdev = dfl_fpga_feature_devs_enumerate(info); |
---|
162 | 223 | if (IS_ERR(cdev)) { |
---|
163 | 224 | dev_err(&pcidev->dev, "Enumeration failure\n"); |
---|
164 | 225 | ret = PTR_ERR(cdev); |
---|
165 | | - goto enum_info_free_exit; |
---|
| 226 | + goto irq_free_exit; |
---|
166 | 227 | } |
---|
167 | 228 | |
---|
168 | 229 | drvdata->cdev = cdev; |
---|
169 | 230 | |
---|
| 231 | +irq_free_exit: |
---|
| 232 | + if (ret) |
---|
| 233 | + cci_pci_free_irq(pcidev); |
---|
170 | 234 | enum_info_free_exit: |
---|
171 | 235 | dfl_fpga_enum_info_free(info); |
---|
172 | 236 | |
---|
.. | .. |
---|
211 | 275 | } |
---|
212 | 276 | |
---|
213 | 277 | ret = cci_enumerate_feature_devs(pcidev); |
---|
214 | | - if (ret) { |
---|
215 | | - dev_err(&pcidev->dev, "enumeration failure %d.\n", ret); |
---|
216 | | - goto disable_error_report_exit; |
---|
217 | | - } |
---|
| 278 | + if (!ret) |
---|
| 279 | + return ret; |
---|
218 | 280 | |
---|
219 | | - return ret; |
---|
| 281 | + dev_err(&pcidev->dev, "enumeration failure %d.\n", ret); |
---|
220 | 282 | |
---|
221 | 283 | disable_error_report_exit: |
---|
222 | 284 | pci_disable_pcie_error_reporting(pcidev); |
---|
223 | 285 | return ret; |
---|
224 | 286 | } |
---|
225 | 287 | |
---|
| 288 | +static int cci_pci_sriov_configure(struct pci_dev *pcidev, int num_vfs) |
---|
| 289 | +{ |
---|
| 290 | + struct cci_drvdata *drvdata = pci_get_drvdata(pcidev); |
---|
| 291 | + struct dfl_fpga_cdev *cdev = drvdata->cdev; |
---|
| 292 | + |
---|
| 293 | + if (!num_vfs) { |
---|
| 294 | + /* |
---|
| 295 | + * disable SRIOV and then put released ports back to default |
---|
| 296 | + * PF access mode. |
---|
| 297 | + */ |
---|
| 298 | + pci_disable_sriov(pcidev); |
---|
| 299 | + |
---|
| 300 | + dfl_fpga_cdev_config_ports_pf(cdev); |
---|
| 301 | + |
---|
| 302 | + } else { |
---|
| 303 | + int ret; |
---|
| 304 | + |
---|
| 305 | + /* |
---|
| 306 | + * before enable SRIOV, put released ports into VF access mode |
---|
| 307 | + * first of all. |
---|
| 308 | + */ |
---|
| 309 | + ret = dfl_fpga_cdev_config_ports_vf(cdev, num_vfs); |
---|
| 310 | + if (ret) |
---|
| 311 | + return ret; |
---|
| 312 | + |
---|
| 313 | + ret = pci_enable_sriov(pcidev, num_vfs); |
---|
| 314 | + if (ret) { |
---|
| 315 | + dfl_fpga_cdev_config_ports_pf(cdev); |
---|
| 316 | + return ret; |
---|
| 317 | + } |
---|
| 318 | + } |
---|
| 319 | + |
---|
| 320 | + return num_vfs; |
---|
| 321 | +} |
---|
| 322 | + |
---|
226 | 323 | static void cci_pci_remove(struct pci_dev *pcidev) |
---|
227 | 324 | { |
---|
| 325 | + if (dev_is_pf(&pcidev->dev)) |
---|
| 326 | + cci_pci_sriov_configure(pcidev, 0); |
---|
| 327 | + |
---|
228 | 328 | cci_remove_feature_devs(pcidev); |
---|
229 | 329 | pci_disable_pcie_error_reporting(pcidev); |
---|
230 | 330 | } |
---|
.. | .. |
---|
234 | 334 | .id_table = cci_pcie_id_tbl, |
---|
235 | 335 | .probe = cci_pci_probe, |
---|
236 | 336 | .remove = cci_pci_remove, |
---|
| 337 | + .sriov_configure = cci_pci_sriov_configure, |
---|
237 | 338 | }; |
---|
238 | 339 | |
---|
239 | 340 | module_pci_driver(cci_pci_driver); |
---|