1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (C) 2023 Intel Corporation */ |
3 | |
4 | #include "idpf.h" |
5 | #include "idpf_devids.h" |
6 | #include "idpf_virtchnl.h" |
7 | |
8 | #define DRV_SUMMARY "Intel(R) Infrastructure Data Path Function Linux Driver" |
9 | |
10 | MODULE_DESCRIPTION(DRV_SUMMARY); |
11 | MODULE_LICENSE("GPL" ); |
12 | |
13 | /** |
14 | * idpf_remove - Device removal routine |
15 | * @pdev: PCI device information struct |
16 | */ |
17 | static void idpf_remove(struct pci_dev *pdev) |
18 | { |
19 | struct idpf_adapter *adapter = pci_get_drvdata(pdev); |
20 | int i; |
21 | |
22 | set_bit(nr: IDPF_REMOVE_IN_PROG, addr: adapter->flags); |
23 | |
24 | /* Wait until vc_event_task is done to consider if any hard reset is |
25 | * in progress else we may go ahead and release the resources but the |
26 | * thread doing the hard reset might continue the init path and |
27 | * end up in bad state. |
28 | */ |
29 | cancel_delayed_work_sync(dwork: &adapter->vc_event_task); |
30 | if (adapter->num_vfs) |
31 | idpf_sriov_configure(pdev, num_vfs: 0); |
32 | |
33 | idpf_vc_core_deinit(adapter); |
34 | |
35 | /* Be a good citizen and leave the device clean on exit */ |
36 | adapter->dev_ops.reg_ops.trigger_reset(adapter, IDPF_HR_FUNC_RESET); |
37 | idpf_deinit_dflt_mbx(adapter); |
38 | |
39 | if (!adapter->netdevs) |
40 | goto destroy_wqs; |
41 | |
42 | /* There are some cases where it's possible to still have netdevs |
43 | * registered with the stack at this point, e.g. if the driver detected |
44 | * a HW reset and rmmod is called before it fully recovers. Unregister |
45 | * any stale netdevs here. |
46 | */ |
47 | for (i = 0; i < adapter->max_vports; i++) { |
48 | if (!adapter->netdevs[i]) |
49 | continue; |
50 | if (adapter->netdevs[i]->reg_state != NETREG_UNINITIALIZED) |
51 | unregister_netdev(dev: adapter->netdevs[i]); |
52 | free_netdev(dev: adapter->netdevs[i]); |
53 | adapter->netdevs[i] = NULL; |
54 | } |
55 | |
56 | destroy_wqs: |
57 | destroy_workqueue(wq: adapter->init_wq); |
58 | destroy_workqueue(wq: adapter->serv_wq); |
59 | destroy_workqueue(wq: adapter->mbx_wq); |
60 | destroy_workqueue(wq: adapter->stats_wq); |
61 | destroy_workqueue(wq: adapter->vc_event_wq); |
62 | |
63 | for (i = 0; i < adapter->max_vports; i++) { |
64 | kfree(objp: adapter->vport_config[i]); |
65 | adapter->vport_config[i] = NULL; |
66 | } |
67 | kfree(objp: adapter->vport_config); |
68 | adapter->vport_config = NULL; |
69 | kfree(objp: adapter->netdevs); |
70 | adapter->netdevs = NULL; |
71 | kfree(objp: adapter->vcxn_mngr); |
72 | adapter->vcxn_mngr = NULL; |
73 | |
74 | mutex_destroy(lock: &adapter->vport_ctrl_lock); |
75 | mutex_destroy(lock: &adapter->vector_lock); |
76 | mutex_destroy(lock: &adapter->queue_lock); |
77 | mutex_destroy(lock: &adapter->vc_buf_lock); |
78 | |
79 | pci_set_drvdata(pdev, NULL); |
80 | kfree(objp: adapter); |
81 | } |
82 | |
83 | /** |
84 | * idpf_shutdown - PCI callback for shutting down device |
85 | * @pdev: PCI device information struct |
86 | */ |
87 | static void idpf_shutdown(struct pci_dev *pdev) |
88 | { |
89 | idpf_remove(pdev); |
90 | |
91 | if (system_state == SYSTEM_POWER_OFF) |
92 | pci_set_power_state(dev: pdev, PCI_D3hot); |
93 | } |
94 | |
95 | /** |
96 | * idpf_cfg_hw - Initialize HW struct |
97 | * @adapter: adapter to setup hw struct for |
98 | * |
99 | * Returns 0 on success, negative on failure |
100 | */ |
101 | static int idpf_cfg_hw(struct idpf_adapter *adapter) |
102 | { |
103 | struct pci_dev *pdev = adapter->pdev; |
104 | struct idpf_hw *hw = &adapter->hw; |
105 | |
106 | hw->hw_addr = pcim_iomap_table(pdev)[0]; |
107 | if (!hw->hw_addr) { |
108 | pci_err(pdev, "failed to allocate PCI iomap table\n" ); |
109 | |
110 | return -ENOMEM; |
111 | } |
112 | |
113 | hw->back = adapter; |
114 | |
115 | return 0; |
116 | } |
117 | |
118 | /** |
119 | * idpf_probe - Device initialization routine |
120 | * @pdev: PCI device information struct |
121 | * @ent: entry in idpf_pci_tbl |
122 | * |
123 | * Returns 0 on success, negative on failure |
124 | */ |
125 | static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
126 | { |
127 | struct device *dev = &pdev->dev; |
128 | struct idpf_adapter *adapter; |
129 | int err; |
130 | |
131 | adapter = kzalloc(size: sizeof(*adapter), GFP_KERNEL); |
132 | if (!adapter) |
133 | return -ENOMEM; |
134 | |
135 | adapter->req_tx_splitq = true; |
136 | adapter->req_rx_splitq = true; |
137 | |
138 | switch (ent->device) { |
139 | case IDPF_DEV_ID_PF: |
140 | idpf_dev_ops_init(adapter); |
141 | break; |
142 | case IDPF_DEV_ID_VF: |
143 | idpf_vf_dev_ops_init(adapter); |
144 | adapter->crc_enable = true; |
145 | break; |
146 | default: |
147 | err = -ENODEV; |
148 | dev_err(&pdev->dev, "Unexpected dev ID 0x%x in idpf probe\n" , |
149 | ent->device); |
150 | goto err_free; |
151 | } |
152 | |
153 | adapter->pdev = pdev; |
154 | err = pcim_enable_device(pdev); |
155 | if (err) |
156 | goto err_free; |
157 | |
158 | err = pcim_iomap_regions(pdev, BIT(0), name: pci_name(pdev)); |
159 | if (err) { |
160 | pci_err(pdev, "pcim_iomap_regions failed %pe\n" , ERR_PTR(err)); |
161 | |
162 | goto err_free; |
163 | } |
164 | |
165 | /* set up for high or low dma */ |
166 | err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); |
167 | if (err) { |
168 | pci_err(pdev, "DMA configuration failed: %pe\n" , ERR_PTR(err)); |
169 | |
170 | goto err_free; |
171 | } |
172 | |
173 | pci_set_master(dev: pdev); |
174 | pci_set_drvdata(pdev, data: adapter); |
175 | |
176 | adapter->init_wq = alloc_workqueue(fmt: "%s-%s-init" , flags: 0, max_active: 0, |
177 | dev_driver_string(dev), |
178 | dev_name(dev)); |
179 | if (!adapter->init_wq) { |
180 | dev_err(dev, "Failed to allocate init workqueue\n" ); |
181 | err = -ENOMEM; |
182 | goto err_free; |
183 | } |
184 | |
185 | adapter->serv_wq = alloc_workqueue(fmt: "%s-%s-service" , flags: 0, max_active: 0, |
186 | dev_driver_string(dev), |
187 | dev_name(dev)); |
188 | if (!adapter->serv_wq) { |
189 | dev_err(dev, "Failed to allocate service workqueue\n" ); |
190 | err = -ENOMEM; |
191 | goto err_serv_wq_alloc; |
192 | } |
193 | |
194 | adapter->mbx_wq = alloc_workqueue(fmt: "%s-%s-mbx" , flags: 0, max_active: 0, |
195 | dev_driver_string(dev), |
196 | dev_name(dev)); |
197 | if (!adapter->mbx_wq) { |
198 | dev_err(dev, "Failed to allocate mailbox workqueue\n" ); |
199 | err = -ENOMEM; |
200 | goto err_mbx_wq_alloc; |
201 | } |
202 | |
203 | adapter->stats_wq = alloc_workqueue(fmt: "%s-%s-stats" , flags: 0, max_active: 0, |
204 | dev_driver_string(dev), |
205 | dev_name(dev)); |
206 | if (!adapter->stats_wq) { |
207 | dev_err(dev, "Failed to allocate workqueue\n" ); |
208 | err = -ENOMEM; |
209 | goto err_stats_wq_alloc; |
210 | } |
211 | |
212 | adapter->vc_event_wq = alloc_workqueue(fmt: "%s-%s-vc_event" , flags: 0, max_active: 0, |
213 | dev_driver_string(dev), |
214 | dev_name(dev)); |
215 | if (!adapter->vc_event_wq) { |
216 | dev_err(dev, "Failed to allocate virtchnl event workqueue\n" ); |
217 | err = -ENOMEM; |
218 | goto err_vc_event_wq_alloc; |
219 | } |
220 | |
221 | /* setup msglvl */ |
222 | adapter->msg_enable = netif_msg_init(debug_value: -1, IDPF_AVAIL_NETIF_M); |
223 | |
224 | err = idpf_cfg_hw(adapter); |
225 | if (err) { |
226 | dev_err(dev, "Failed to configure HW structure for adapter: %d\n" , |
227 | err); |
228 | goto err_cfg_hw; |
229 | } |
230 | |
231 | mutex_init(&adapter->vport_ctrl_lock); |
232 | mutex_init(&adapter->vector_lock); |
233 | mutex_init(&adapter->queue_lock); |
234 | mutex_init(&adapter->vc_buf_lock); |
235 | |
236 | INIT_DELAYED_WORK(&adapter->init_task, idpf_init_task); |
237 | INIT_DELAYED_WORK(&adapter->serv_task, idpf_service_task); |
238 | INIT_DELAYED_WORK(&adapter->mbx_task, idpf_mbx_task); |
239 | INIT_DELAYED_WORK(&adapter->stats_task, idpf_statistics_task); |
240 | INIT_DELAYED_WORK(&adapter->vc_event_task, idpf_vc_event_task); |
241 | |
242 | adapter->dev_ops.reg_ops.reset_reg_init(adapter); |
243 | set_bit(nr: IDPF_HR_DRV_LOAD, addr: adapter->flags); |
244 | queue_delayed_work(wq: adapter->vc_event_wq, dwork: &adapter->vc_event_task, |
245 | delay: msecs_to_jiffies(m: 10 * (pdev->devfn & 0x07))); |
246 | |
247 | return 0; |
248 | |
249 | err_cfg_hw: |
250 | destroy_workqueue(wq: adapter->vc_event_wq); |
251 | err_vc_event_wq_alloc: |
252 | destroy_workqueue(wq: adapter->stats_wq); |
253 | err_stats_wq_alloc: |
254 | destroy_workqueue(wq: adapter->mbx_wq); |
255 | err_mbx_wq_alloc: |
256 | destroy_workqueue(wq: adapter->serv_wq); |
257 | err_serv_wq_alloc: |
258 | destroy_workqueue(wq: adapter->init_wq); |
259 | err_free: |
260 | kfree(objp: adapter); |
261 | return err; |
262 | } |
263 | |
264 | /* idpf_pci_tbl - PCI Dev idpf ID Table |
265 | */ |
266 | static const struct pci_device_id idpf_pci_tbl[] = { |
267 | { PCI_VDEVICE(INTEL, IDPF_DEV_ID_PF)}, |
268 | { PCI_VDEVICE(INTEL, IDPF_DEV_ID_VF)}, |
269 | { /* Sentinel */ } |
270 | }; |
271 | MODULE_DEVICE_TABLE(pci, idpf_pci_tbl); |
272 | |
273 | static struct pci_driver idpf_driver = { |
274 | .name = KBUILD_MODNAME, |
275 | .id_table = idpf_pci_tbl, |
276 | .probe = idpf_probe, |
277 | .sriov_configure = idpf_sriov_configure, |
278 | .remove = idpf_remove, |
279 | .shutdown = idpf_shutdown, |
280 | }; |
281 | module_pci_driver(idpf_driver); |
282 | |