Commit | Line | Data |
---|---|---|
ae06c70b | 1 | // SPDX-License-Identifier: GPL-2.0 |
51dce24b | 2 | /* Copyright(c) 2013 - 2018 Intel Corporation. */ |
883a9ccb AD |
3 | |
4 | #include "fm10k.h" | |
5 | #include "fm10k_vf.h" | |
6 | #include "fm10k_pf.h" | |
7 | ||
8 | static s32 fm10k_iov_msg_error(struct fm10k_hw *hw, u32 **results, | |
9 | struct fm10k_mbx_info *mbx) | |
10 | { | |
11 | struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; | |
12 | struct fm10k_intfc *interface = hw->back; | |
13 | struct pci_dev *pdev = interface->pdev; | |
14 | ||
15 | dev_err(&pdev->dev, "Unknown message ID %u on VF %d\n", | |
16 | **results & FM10K_TLV_ID_MASK, vf_info->vf_idx); | |
17 | ||
18 | return fm10k_tlv_msg_error(hw, results, mbx); | |
19 | } | |
20 | ||
1f5c27e5 JK |
21 | /** |
22 | * fm10k_iov_msg_queue_mac_vlan - Message handler for MAC/VLAN request from VF | |
23 | * @hw: Pointer to hardware structure | |
24 | * @results: Pointer array to message, results[0] is pointer to message | |
25 | * @mbx: Pointer to mailbox information structure | |
26 | * | |
27 | * This function is a custom handler for MAC/VLAN requests from the VF. The | |
28 | * assumption is that it is acceptable to directly hand off the message from | |
29 | * the VF to the PF's switch manager. However, we use a MAC/VLAN message | |
30 | * queue to avoid overloading the mailbox when a large number of requests | |
31 | * come in. | |
32 | **/ | |
33 | static s32 fm10k_iov_msg_queue_mac_vlan(struct fm10k_hw *hw, u32 **results, | |
34 | struct fm10k_mbx_info *mbx) | |
35 | { | |
36 | struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; | |
37 | struct fm10k_intfc *interface = hw->back; | |
38 | u8 mac[ETH_ALEN]; | |
39 | u32 *result; | |
40 | int err = 0; | |
41 | bool set; | |
42 | u16 vlan; | |
43 | u32 vid; | |
44 | ||
45 | /* we shouldn't be updating rules on a disabled interface */ | |
46 | if (!FM10K_VF_FLAG_ENABLED(vf_info)) | |
47 | err = FM10K_ERR_PARAM; | |
48 | ||
49 | if (!err && !!results[FM10K_MAC_VLAN_MSG_VLAN]) { | |
50 | result = results[FM10K_MAC_VLAN_MSG_VLAN]; | |
51 | ||
52 | /* record VLAN id requested */ | |
53 | err = fm10k_tlv_attr_get_u32(result, &vid); | |
54 | if (err) | |
55 | return err; | |
56 | ||
57 | set = !(vid & FM10K_VLAN_CLEAR); | |
58 | vid &= ~FM10K_VLAN_CLEAR; | |
59 | ||
60 | /* if the length field has been set, this is a multi-bit | |
61 | * update request. For multi-bit requests, simply disallow | |
62 | * them when the pf_vid has been set. In this case, the PF | |
63 | * should have already cleared the VLAN_TABLE, and if we | |
64 | * allowed them, it could allow a rogue VF to receive traffic | |
65 | * on a VLAN it was not assigned. In the single-bit case, we | |
66 | * need to modify requests for VLAN 0 to use the default PF or | |
67 | * SW vid when assigned. | |
68 | */ | |
69 | ||
70 | if (vid >> 16) { | |
71 | /* prevent multi-bit requests when PF has | |
72 | * administratively set the VLAN for this VF | |
73 | */ | |
74 | if (vf_info->pf_vid) | |
75 | return FM10K_ERR_PARAM; | |
76 | } else { | |
77 | err = fm10k_iov_select_vid(vf_info, (u16)vid); | |
78 | if (err < 0) | |
79 | return err; | |
80 | ||
81 | vid = err; | |
82 | } | |
83 | ||
84 | /* update VSI info for VF in regards to VLAN table */ | |
85 | err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, set); | |
86 | } | |
87 | ||
88 | if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) { | |
89 | result = results[FM10K_MAC_VLAN_MSG_MAC]; | |
90 | ||
91 | /* record unicast MAC address requested */ | |
92 | err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); | |
93 | if (err) | |
94 | return err; | |
95 | ||
96 | /* block attempts to set MAC for a locked device */ | |
97 | if (is_valid_ether_addr(vf_info->mac) && | |
98 | !ether_addr_equal(mac, vf_info->mac)) | |
99 | return FM10K_ERR_PARAM; | |
100 | ||
101 | set = !(vlan & FM10K_VLAN_CLEAR); | |
102 | vlan &= ~FM10K_VLAN_CLEAR; | |
103 | ||
104 | err = fm10k_iov_select_vid(vf_info, vlan); | |
105 | if (err < 0) | |
106 | return err; | |
107 | ||
108 | vlan = (u16)err; | |
109 | ||
110 | /* Add this request to the MAC/VLAN queue */ | |
111 | err = fm10k_queue_mac_request(interface, vf_info->glort, | |
112 | mac, vlan, set); | |
113 | } | |
114 | ||
115 | if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) { | |
116 | result = results[FM10K_MAC_VLAN_MSG_MULTICAST]; | |
117 | ||
118 | /* record multicast MAC address requested */ | |
119 | err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan); | |
120 | if (err) | |
121 | return err; | |
122 | ||
123 | /* verify that the VF is allowed to request multicast */ | |
124 | if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED)) | |
125 | return FM10K_ERR_PARAM; | |
126 | ||
127 | set = !(vlan & FM10K_VLAN_CLEAR); | |
128 | vlan &= ~FM10K_VLAN_CLEAR; | |
129 | ||
130 | err = fm10k_iov_select_vid(vf_info, vlan); | |
131 | if (err < 0) | |
132 | return err; | |
133 | ||
134 | vlan = (u16)err; | |
135 | ||
136 | /* Add this request to the MAC/VLAN queue */ | |
137 | err = fm10k_queue_mac_request(interface, vf_info->glort, | |
138 | mac, vlan, set); | |
139 | } | |
140 | ||
141 | return err; | |
142 | } | |
143 | ||
883a9ccb AD |
144 | static const struct fm10k_msg_data iov_mbx_data[] = { |
145 | FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), | |
146 | FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf), | |
1f5c27e5 | 147 | FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_queue_mac_vlan), |
883a9ccb AD |
148 | FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf), |
149 | FM10K_TLV_MSG_ERROR_HANDLER(fm10k_iov_msg_error), | |
150 | }; | |
151 | ||
152 | s32 fm10k_iov_event(struct fm10k_intfc *interface) | |
153 | { | |
154 | struct fm10k_hw *hw = &interface->hw; | |
155 | struct fm10k_iov_data *iov_data; | |
9de15bda | 156 | s64 vflre; |
883a9ccb AD |
157 | int i; |
158 | ||
d8ec92f2 | 159 | /* if there is no iov_data then there is no mailbox to process */ |
ce4dad2c | 160 | if (!READ_ONCE(interface->iov_data)) |
883a9ccb AD |
161 | return 0; |
162 | ||
163 | rcu_read_lock(); | |
164 | ||
165 | iov_data = interface->iov_data; | |
166 | ||
167 | /* check again now that we are in the RCU block */ | |
168 | if (!iov_data) | |
169 | goto read_unlock; | |
170 | ||
171 | if (!(fm10k_read_reg(hw, FM10K_EICR) & FM10K_EICR_VFLR)) | |
9de15bda | 172 | goto read_unlock; |
883a9ccb AD |
173 | |
174 | /* read VFLRE to determine if any VFs have been reset */ | |
d876c158 JK |
175 | vflre = fm10k_read_reg(hw, FM10K_PFVFLRE(1)); |
176 | vflre <<= 32; | |
177 | vflre |= fm10k_read_reg(hw, FM10K_PFVFLRE(0)); | |
883a9ccb | 178 | |
d876c158 | 179 | i = iov_data->num_vfs; |
883a9ccb | 180 | |
d876c158 JK |
181 | for (vflre <<= 64 - i; vflre && i--; vflre += vflre) { |
182 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | |
883a9ccb | 183 | |
d876c158 JK |
184 | if (vflre >= 0) |
185 | continue; | |
883a9ccb | 186 | |
d876c158 JK |
187 | hw->iov.ops.reset_resources(hw, vf_info); |
188 | vf_info->mbx.ops.connect(hw, &vf_info->mbx); | |
189 | } | |
883a9ccb | 190 | |
883a9ccb AD |
191 | read_unlock: |
192 | rcu_read_unlock(); | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | s32 fm10k_iov_mbx(struct fm10k_intfc *interface) | |
198 | { | |
199 | struct fm10k_hw *hw = &interface->hw; | |
200 | struct fm10k_iov_data *iov_data; | |
201 | int i; | |
202 | ||
d8ec92f2 | 203 | /* if there is no iov_data then there is no mailbox to process */ |
ce4dad2c | 204 | if (!READ_ONCE(interface->iov_data)) |
883a9ccb AD |
205 | return 0; |
206 | ||
207 | rcu_read_lock(); | |
208 | ||
209 | iov_data = interface->iov_data; | |
210 | ||
211 | /* check again now that we are in the RCU block */ | |
212 | if (!iov_data) | |
213 | goto read_unlock; | |
214 | ||
215 | /* lock the mailbox for transmit and receive */ | |
216 | fm10k_mbx_lock(interface); | |
217 | ||
ada2411d JK |
218 | /* Most VF messages sent to the PF cause the PF to respond by |
219 | * requesting from the SM mailbox. This means that too many VF | |
220 | * messages processed at once could cause a mailbox timeout on the PF. | |
221 | * To prevent this, store a pointer to the next VF mbx to process. Use | |
222 | * that as the start of the loop so that we don't starve whichever VF | |
223 | * got ignored on the previous run. | |
224 | */ | |
883a9ccb AD |
225 | process_mbx: |
226 | for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) { | |
227 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | |
228 | struct fm10k_mbx_info *mbx = &vf_info->mbx; | |
229 | u16 glort = vf_info->glort; | |
230 | ||
17a91809 JK |
231 | /* process the SM mailbox first to drain outgoing messages */ |
232 | hw->mbx.ops.process(hw, &hw->mbx); | |
233 | ||
883a9ccb | 234 | /* verify port mapping is valid, if not reset port */ |
1f5c27e5 | 235 | if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort)) { |
883a9ccb | 236 | hw->iov.ops.reset_lport(hw, vf_info); |
1f5c27e5 JK |
237 | fm10k_clear_macvlan_queue(interface, glort, false); |
238 | } | |
883a9ccb AD |
239 | |
240 | /* reset VFs that have mailbox timed out */ | |
241 | if (!mbx->timeout) { | |
242 | hw->iov.ops.reset_resources(hw, vf_info); | |
243 | mbx->ops.connect(hw, mbx); | |
244 | } | |
245 | ||
883a9ccb | 246 | /* guarantee we have free space in the SM mailbox */ |
e69e40c8 NMK |
247 | if (hw->mbx.state == FM10K_STATE_OPEN && |
248 | !hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) { | |
80043f3b JK |
249 | /* keep track of how many times this occurs */ |
250 | interface->hw_sm_mbx_full++; | |
b52b7f70 JK |
251 | |
252 | /* make sure we try again momentarily */ | |
253 | fm10k_service_event_schedule(interface); | |
254 | ||
883a9ccb | 255 | break; |
80043f3b | 256 | } |
883a9ccb AD |
257 | |
258 | /* cleanup mailbox and process received messages */ | |
259 | mbx->ops.process(hw, mbx); | |
260 | } | |
261 | ||
ada2411d JK |
262 | /* if we stopped processing mailboxes early, update next_vf_mbx. |
263 | * Otherwise, reset next_vf_mbx, and restart loop so that we process | |
264 | * the remaining mailboxes we skipped at the start. | |
265 | */ | |
883a9ccb AD |
266 | if (i >= 0) { |
267 | iov_data->next_vf_mbx = i + 1; | |
268 | } else if (iov_data->next_vf_mbx) { | |
269 | iov_data->next_vf_mbx = 0; | |
270 | goto process_mbx; | |
271 | } | |
272 | ||
273 | /* free the lock */ | |
274 | fm10k_mbx_unlock(interface); | |
275 | ||
276 | read_unlock: | |
277 | rcu_read_unlock(); | |
278 | ||
279 | return 0; | |
280 | } | |
281 | ||
282 | void fm10k_iov_suspend(struct pci_dev *pdev) | |
283 | { | |
284 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | |
285 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
286 | struct fm10k_hw *hw = &interface->hw; | |
287 | int num_vfs, i; | |
288 | ||
289 | /* pull out num_vfs from iov_data */ | |
290 | num_vfs = iov_data ? iov_data->num_vfs : 0; | |
291 | ||
292 | /* shut down queue mapping for VFs */ | |
293 | fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_vf_rss), | |
294 | FM10K_DGLORTMAP_NONE); | |
295 | ||
296 | /* Stop any active VFs and reset their resources */ | |
297 | for (i = 0; i < num_vfs; i++) { | |
298 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | |
299 | ||
300 | hw->iov.ops.reset_resources(hw, vf_info); | |
301 | hw->iov.ops.reset_lport(hw, vf_info); | |
1f5c27e5 | 302 | fm10k_clear_macvlan_queue(interface, vf_info->glort, false); |
883a9ccb AD |
303 | } |
304 | } | |
305 | ||
e330af78 JK |
306 | static void fm10k_mask_aer_comp_abort(struct pci_dev *pdev) |
307 | { | |
308 | u32 err_mask; | |
309 | int pos; | |
310 | ||
311 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); | |
312 | if (!pos) | |
313 | return; | |
314 | ||
315 | /* Mask the completion abort bit in the ERR_UNCOR_MASK register, | |
316 | * preventing the device from reporting these errors to the upstream | |
317 | * PCIe root device. This avoids bringing down platforms which upgrade | |
318 | * non-fatal completer aborts into machine check exceptions. Completer | |
319 | * aborts can occur whenever a VF reads a queue it doesn't own. | |
320 | */ | |
321 | pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, &err_mask); | |
322 | err_mask |= PCI_ERR_UNC_COMP_ABORT; | |
323 | pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, err_mask); | |
324 | ||
325 | mmiowb(); | |
326 | } | |
327 | ||
883a9ccb AD |
328 | int fm10k_iov_resume(struct pci_dev *pdev) |
329 | { | |
330 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | |
331 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
332 | struct fm10k_dglort_cfg dglort = { 0 }; | |
333 | struct fm10k_hw *hw = &interface->hw; | |
334 | int num_vfs, i; | |
335 | ||
336 | /* pull out num_vfs from iov_data */ | |
337 | num_vfs = iov_data ? iov_data->num_vfs : 0; | |
338 | ||
339 | /* return error if iov_data is not already populated */ | |
340 | if (!iov_data) | |
341 | return -ENOMEM; | |
342 | ||
e330af78 JK |
343 | /* Lower severity of completer abort error reporting as |
344 | * the VFs can trigger this any time they read a queue | |
345 | * that they don't own. | |
346 | */ | |
347 | fm10k_mask_aer_comp_abort(pdev); | |
348 | ||
883a9ccb AD |
349 | /* allocate hardware resources for the VFs */ |
350 | hw->iov.ops.assign_resources(hw, num_vfs, num_vfs); | |
351 | ||
352 | /* configure DGLORT mapping for RSS */ | |
353 | dglort.glort = hw->mac.dglort_map & FM10K_DGLORTMAP_NONE; | |
354 | dglort.idx = fm10k_dglort_vf_rss; | |
355 | dglort.inner_rss = 1; | |
356 | dglort.rss_l = fls(fm10k_queues_per_pool(hw) - 1); | |
357 | dglort.queue_b = fm10k_vf_queue_index(hw, 0); | |
358 | dglort.vsi_l = fls(hw->iov.total_vfs - 1); | |
359 | dglort.vsi_b = 1; | |
360 | ||
361 | hw->mac.ops.configure_dglort_map(hw, &dglort); | |
362 | ||
363 | /* assign resources to the device */ | |
364 | for (i = 0; i < num_vfs; i++) { | |
365 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | |
366 | ||
367 | /* allocate all but the last GLORT to the VFs */ | |
c8eeacb3 | 368 | if (i == (~hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT)) |
883a9ccb AD |
369 | break; |
370 | ||
371 | /* assign GLORT to VF, and restrict it to multicast */ | |
372 | hw->iov.ops.set_lport(hw, vf_info, i, | |
373 | FM10K_VF_FLAG_MULTI_CAPABLE); | |
374 | ||
883a9ccb AD |
375 | /* mailbox is disconnected so we don't send a message */ |
376 | hw->iov.ops.assign_default_mac_vlan(hw, vf_info); | |
377 | ||
378 | /* now we are ready so we can connect */ | |
379 | vf_info->mbx.ops.connect(hw, &vf_info->mbx); | |
380 | } | |
381 | ||
382 | return 0; | |
383 | } | |
384 | ||
385 | s32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid) | |
386 | { | |
387 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
388 | struct fm10k_hw *hw = &interface->hw; | |
389 | struct fm10k_vf_info *vf_info; | |
390 | u16 vf_idx = (glort - hw->mac.dglort_map) & FM10K_DGLORTMAP_NONE; | |
391 | ||
392 | /* no IOV support, not our message to process */ | |
393 | if (!iov_data) | |
394 | return FM10K_ERR_PARAM; | |
395 | ||
396 | /* glort outside our range, not our message to process */ | |
397 | if (vf_idx >= iov_data->num_vfs) | |
398 | return FM10K_ERR_PARAM; | |
399 | ||
eca32047 | 400 | /* determine if an update has occurred and if so notify the VF */ |
883a9ccb AD |
401 | vf_info = &iov_data->vf_info[vf_idx]; |
402 | if (vf_info->sw_vid != pvid) { | |
403 | vf_info->sw_vid = pvid; | |
404 | hw->iov.ops.assign_default_mac_vlan(hw, vf_info); | |
405 | } | |
406 | ||
407 | return 0; | |
408 | } | |
409 | ||
410 | static void fm10k_iov_free_data(struct pci_dev *pdev) | |
411 | { | |
412 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | |
413 | ||
414 | if (!interface->iov_data) | |
415 | return; | |
416 | ||
417 | /* reclaim hardware resources */ | |
418 | fm10k_iov_suspend(pdev); | |
419 | ||
420 | /* drop iov_data from interface */ | |
421 | kfree_rcu(interface->iov_data, rcu); | |
422 | interface->iov_data = NULL; | |
423 | } | |
424 | ||
425 | static s32 fm10k_iov_alloc_data(struct pci_dev *pdev, int num_vfs) | |
426 | { | |
427 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | |
428 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
429 | struct fm10k_hw *hw = &interface->hw; | |
430 | size_t size; | |
431 | int i, err; | |
432 | ||
433 | /* return error if iov_data is already populated */ | |
434 | if (iov_data) | |
435 | return -EBUSY; | |
436 | ||
437 | /* The PF should always be able to assign resources */ | |
438 | if (!hw->iov.ops.assign_resources) | |
439 | return -ENODEV; | |
440 | ||
441 | /* nothing to do if no VFs are requested */ | |
442 | if (!num_vfs) | |
443 | return 0; | |
444 | ||
445 | /* allocate memory for VF storage */ | |
446 | size = offsetof(struct fm10k_iov_data, vf_info[num_vfs]); | |
447 | iov_data = kzalloc(size, GFP_KERNEL); | |
448 | if (!iov_data) | |
449 | return -ENOMEM; | |
450 | ||
451 | /* record number of VFs */ | |
452 | iov_data->num_vfs = num_vfs; | |
453 | ||
454 | /* loop through vf_info structures initializing each entry */ | |
455 | for (i = 0; i < num_vfs; i++) { | |
456 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | |
457 | ||
458 | /* Record VF VSI value */ | |
459 | vf_info->vsi = i + 1; | |
460 | vf_info->vf_idx = i; | |
461 | ||
462 | /* initialize mailbox memory */ | |
463 | err = fm10k_pfvf_mbx_init(hw, &vf_info->mbx, iov_mbx_data, i); | |
464 | if (err) { | |
465 | dev_err(&pdev->dev, | |
466 | "Unable to initialize SR-IOV mailbox\n"); | |
467 | kfree(iov_data); | |
468 | return err; | |
469 | } | |
470 | } | |
471 | ||
472 | /* assign iov_data to interface */ | |
473 | interface->iov_data = iov_data; | |
474 | ||
475 | /* allocate hardware resources for the VFs */ | |
476 | fm10k_iov_resume(pdev); | |
477 | ||
478 | return 0; | |
479 | } | |
480 | ||
481 | void fm10k_iov_disable(struct pci_dev *pdev) | |
482 | { | |
483 | if (pci_num_vf(pdev) && pci_vfs_assigned(pdev)) | |
484 | dev_err(&pdev->dev, | |
485 | "Cannot disable SR-IOV while VFs are assigned\n"); | |
486 | else | |
487 | pci_disable_sriov(pdev); | |
488 | ||
489 | fm10k_iov_free_data(pdev); | |
490 | } | |
491 | ||
883a9ccb AD |
492 | int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs) |
493 | { | |
494 | int current_vfs = pci_num_vf(pdev); | |
495 | int err = 0; | |
496 | ||
497 | if (current_vfs && pci_vfs_assigned(pdev)) { | |
498 | dev_err(&pdev->dev, | |
499 | "Cannot modify SR-IOV while VFs are assigned\n"); | |
500 | num_vfs = current_vfs; | |
501 | } else { | |
502 | pci_disable_sriov(pdev); | |
503 | fm10k_iov_free_data(pdev); | |
504 | } | |
505 | ||
506 | /* allocate resources for the VFs */ | |
507 | err = fm10k_iov_alloc_data(pdev, num_vfs); | |
508 | if (err) | |
509 | return err; | |
510 | ||
511 | /* allocate VFs if not already allocated */ | |
c8eeacb3 | 512 | if (num_vfs && num_vfs != current_vfs) { |
883a9ccb AD |
513 | err = pci_enable_sriov(pdev, num_vfs); |
514 | if (err) { | |
515 | dev_err(&pdev->dev, | |
516 | "Enable PCI SR-IOV failed: %d\n", err); | |
517 | return err; | |
518 | } | |
519 | } | |
520 | ||
521 | return num_vfs; | |
522 | } | |
523 | ||
a38488f5 JK |
524 | static inline void fm10k_reset_vf_info(struct fm10k_intfc *interface, |
525 | struct fm10k_vf_info *vf_info) | |
526 | { | |
527 | struct fm10k_hw *hw = &interface->hw; | |
528 | ||
529 | /* assigning the MAC address will send a mailbox message */ | |
530 | fm10k_mbx_lock(interface); | |
531 | ||
532 | /* disable LPORT for this VF which clears switch rules */ | |
533 | hw->iov.ops.reset_lport(hw, vf_info); | |
534 | ||
1f5c27e5 JK |
535 | fm10k_clear_macvlan_queue(interface, vf_info->glort, false); |
536 | ||
a38488f5 JK |
537 | /* assign new MAC+VLAN for this VF */ |
538 | hw->iov.ops.assign_default_mac_vlan(hw, vf_info); | |
539 | ||
540 | /* re-enable the LPORT for this VF */ | |
541 | hw->iov.ops.set_lport(hw, vf_info, vf_info->vf_idx, | |
542 | FM10K_VF_FLAG_MULTI_CAPABLE); | |
543 | ||
544 | fm10k_mbx_unlock(interface); | |
545 | } | |
546 | ||
883a9ccb AD |
547 | int fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac) |
548 | { | |
549 | struct fm10k_intfc *interface = netdev_priv(netdev); | |
550 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
883a9ccb AD |
551 | struct fm10k_vf_info *vf_info; |
552 | ||
553 | /* verify SR-IOV is active and that vf idx is valid */ | |
554 | if (!iov_data || vf_idx >= iov_data->num_vfs) | |
555 | return -EINVAL; | |
556 | ||
557 | /* verify MAC addr is valid */ | |
558 | if (!is_zero_ether_addr(mac) && !is_valid_ether_addr(mac)) | |
559 | return -EINVAL; | |
560 | ||
561 | /* record new MAC address */ | |
562 | vf_info = &iov_data->vf_info[vf_idx]; | |
563 | ether_addr_copy(vf_info->mac, mac); | |
564 | ||
a38488f5 | 565 | fm10k_reset_vf_info(interface, vf_info); |
883a9ccb AD |
566 | |
567 | return 0; | |
568 | } | |
569 | ||
570 | int fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid, | |
79aab093 | 571 | u8 qos, __be16 vlan_proto) |
883a9ccb AD |
572 | { |
573 | struct fm10k_intfc *interface = netdev_priv(netdev); | |
574 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
575 | struct fm10k_hw *hw = &interface->hw; | |
576 | struct fm10k_vf_info *vf_info; | |
577 | ||
578 | /* verify SR-IOV is active and that vf idx is valid */ | |
579 | if (!iov_data || vf_idx >= iov_data->num_vfs) | |
580 | return -EINVAL; | |
581 | ||
582 | /* QOS is unsupported and VLAN IDs accepted range 0-4094 */ | |
583 | if (qos || (vid > (VLAN_VID_MASK - 1))) | |
584 | return -EINVAL; | |
585 | ||
79aab093 MS |
586 | /* VF VLAN Protocol part to default is unsupported */ |
587 | if (vlan_proto != htons(ETH_P_8021Q)) | |
588 | return -EPROTONOSUPPORT; | |
589 | ||
883a9ccb AD |
590 | vf_info = &iov_data->vf_info[vf_idx]; |
591 | ||
592 | /* exit if there is nothing to do */ | |
593 | if (vf_info->pf_vid == vid) | |
594 | return 0; | |
595 | ||
596 | /* record default VLAN ID for VF */ | |
597 | vf_info->pf_vid = vid; | |
598 | ||
883a9ccb AD |
599 | /* Clear the VLAN table for the VF */ |
600 | hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, vf_info->vsi, false); | |
601 | ||
a38488f5 | 602 | fm10k_reset_vf_info(interface, vf_info); |
883a9ccb AD |
603 | |
604 | return 0; | |
605 | } | |
606 | ||
de445199 | 607 | int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, |
3e256ac5 | 608 | int __always_unused min_rate, int max_rate) |
883a9ccb AD |
609 | { |
610 | struct fm10k_intfc *interface = netdev_priv(netdev); | |
611 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
612 | struct fm10k_hw *hw = &interface->hw; | |
613 | ||
614 | /* verify SR-IOV is active and that vf idx is valid */ | |
615 | if (!iov_data || vf_idx >= iov_data->num_vfs) | |
616 | return -EINVAL; | |
617 | ||
618 | /* rate limit cannot be less than 10Mbs or greater than link speed */ | |
3e256ac5 JK |
619 | if (max_rate && |
620 | (max_rate < FM10K_VF_TC_MIN || max_rate > FM10K_VF_TC_MAX)) | |
883a9ccb AD |
621 | return -EINVAL; |
622 | ||
623 | /* store values */ | |
3e256ac5 | 624 | iov_data->vf_info[vf_idx].rate = max_rate; |
883a9ccb AD |
625 | |
626 | /* update hardware configuration */ | |
3e256ac5 | 627 | hw->iov.ops.configure_tc(hw, vf_idx, max_rate); |
883a9ccb AD |
628 | |
629 | return 0; | |
630 | } | |
631 | ||
632 | int fm10k_ndo_get_vf_config(struct net_device *netdev, | |
633 | int vf_idx, struct ifla_vf_info *ivi) | |
634 | { | |
635 | struct fm10k_intfc *interface = netdev_priv(netdev); | |
636 | struct fm10k_iov_data *iov_data = interface->iov_data; | |
637 | struct fm10k_vf_info *vf_info; | |
638 | ||
639 | /* verify SR-IOV is active and that vf idx is valid */ | |
640 | if (!iov_data || vf_idx >= iov_data->num_vfs) | |
641 | return -EINVAL; | |
642 | ||
643 | vf_info = &iov_data->vf_info[vf_idx]; | |
644 | ||
645 | ivi->vf = vf_idx; | |
646 | ivi->max_tx_rate = vf_info->rate; | |
647 | ivi->min_tx_rate = 0; | |
648 | ether_addr_copy(ivi->mac, vf_info->mac); | |
649 | ivi->vlan = vf_info->pf_vid; | |
650 | ivi->qos = 0; | |
651 | ||
652 | return 0; | |
653 | } |