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