diff options
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k.h | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_iov.c | 536 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 32 |
5 files changed, 614 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/fm10k/Makefile b/drivers/net/ethernet/intel/fm10k/Makefile index f70893a880c5..70565abfc62a 100644 --- a/drivers/net/ethernet/intel/fm10k/Makefile +++ b/drivers/net/ethernet/intel/fm10k/Makefile | |||
@@ -29,4 +29,4 @@ obj-$(CONFIG_FM10K) += fm10k.o | |||
29 | 29 | ||
30 | fm10k-objs := fm10k_main.o fm10k_common.o fm10k_pci.o \ | 30 | fm10k-objs := fm10k_main.o fm10k_common.o fm10k_pci.o \ |
31 | fm10k_netdev.o fm10k_ethtool.o fm10k_pf.o fm10k_vf.o \ | 31 | fm10k_netdev.o fm10k_ethtool.o fm10k_pf.o fm10k_vf.o \ |
32 | fm10k_mbx.o fm10k_tlv.o | 32 | fm10k_mbx.o fm10k_iov.o fm10k_tlv.o |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index 639698c7c108..fb718719c196 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h | |||
@@ -218,6 +218,13 @@ struct fm10k_ring_feature { | |||
218 | u16 offset; /* offset to start of feature */ | 218 | u16 offset; /* offset to start of feature */ |
219 | }; | 219 | }; |
220 | 220 | ||
221 | struct fm10k_iov_data { | ||
222 | unsigned int num_vfs; | ||
223 | unsigned int next_vf_mbx; | ||
224 | struct rcu_head rcu; | ||
225 | struct fm10k_vf_info vf_info[0]; | ||
226 | }; | ||
227 | |||
221 | #define fm10k_vxlan_port_for_each(vp, intfc) \ | 228 | #define fm10k_vxlan_port_for_each(vp, intfc) \ |
222 | list_for_each_entry(vp, &(intfc)->vxlan_port, list) | 229 | list_for_each_entry(vp, &(intfc)->vxlan_port, list) |
223 | struct fm10k_vxlan_port { | 230 | struct fm10k_vxlan_port { |
@@ -277,6 +284,9 @@ struct fm10k_intfc { | |||
277 | int num_q_vectors; /* current number of q_vectors for device */ | 284 | int num_q_vectors; /* current number of q_vectors for device */ |
278 | struct fm10k_ring_feature ring_feature[RING_F_ARRAY_SIZE]; | 285 | struct fm10k_ring_feature ring_feature[RING_F_ARRAY_SIZE]; |
279 | 286 | ||
287 | /* SR-IOV information management structure */ | ||
288 | struct fm10k_iov_data *iov_data; | ||
289 | |||
280 | struct fm10k_hw_stats stats; | 290 | struct fm10k_hw_stats stats; |
281 | struct fm10k_hw hw; | 291 | struct fm10k_hw hw; |
282 | u32 __iomem *uc_addr; | 292 | u32 __iomem *uc_addr; |
@@ -441,4 +451,20 @@ int fm10k_close(struct net_device *netdev); | |||
441 | 451 | ||
442 | /* Ethtool */ | 452 | /* Ethtool */ |
443 | void fm10k_set_ethtool_ops(struct net_device *dev); | 453 | void fm10k_set_ethtool_ops(struct net_device *dev); |
454 | |||
455 | /* IOV */ | ||
456 | s32 fm10k_iov_event(struct fm10k_intfc *interface); | ||
457 | s32 fm10k_iov_mbx(struct fm10k_intfc *interface); | ||
458 | void fm10k_iov_suspend(struct pci_dev *pdev); | ||
459 | int fm10k_iov_resume(struct pci_dev *pdev); | ||
460 | void fm10k_iov_disable(struct pci_dev *pdev); | ||
461 | int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs); | ||
462 | s32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid); | ||
463 | int fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac); | ||
464 | int fm10k_ndo_set_vf_vlan(struct net_device *netdev, | ||
465 | int vf_idx, u16 vid, u8 qos); | ||
466 | int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, int rate, | ||
467 | int unused); | ||
468 | int fm10k_ndo_get_vf_config(struct net_device *netdev, | ||
469 | int vf_idx, struct ifla_vf_info *ivi); | ||
444 | #endif /* _FM10K_H_ */ | 470 | #endif /* _FM10K_H_ */ |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c new file mode 100644 index 000000000000..060190864238 --- /dev/null +++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c | |||
@@ -0,0 +1,536 @@ | |||
1 | /* Intel Ethernet Switch Host Interface Driver | ||
2 | * Copyright(c) 2013 - 2014 Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * The full GNU General Public License is included in this distribution in | ||
14 | * the file called "COPYING". | ||
15 | * | ||
16 | * Contact Information: | ||
17 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
18 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
19 | */ | ||
20 | |||
21 | #include "fm10k.h" | ||
22 | #include "fm10k_vf.h" | ||
23 | #include "fm10k_pf.h" | ||
24 | |||
25 | static s32 fm10k_iov_msg_error(struct fm10k_hw *hw, u32 **results, | ||
26 | struct fm10k_mbx_info *mbx) | ||
27 | { | ||
28 | struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; | ||
29 | struct fm10k_intfc *interface = hw->back; | ||
30 | struct pci_dev *pdev = interface->pdev; | ||
31 | |||
32 | dev_err(&pdev->dev, "Unknown message ID %u on VF %d\n", | ||
33 | **results & FM10K_TLV_ID_MASK, vf_info->vf_idx); | ||
34 | |||
35 | return fm10k_tlv_msg_error(hw, results, mbx); | ||
36 | } | ||
37 | |||
38 | static const struct fm10k_msg_data iov_mbx_data[] = { | ||
39 | FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), | ||
40 | FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf), | ||
41 | FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_mac_vlan_pf), | ||
42 | FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf), | ||
43 | FM10K_TLV_MSG_ERROR_HANDLER(fm10k_iov_msg_error), | ||
44 | }; | ||
45 | |||
46 | s32 fm10k_iov_event(struct fm10k_intfc *interface) | ||
47 | { | ||
48 | struct fm10k_hw *hw = &interface->hw; | ||
49 | struct fm10k_iov_data *iov_data; | ||
50 | s64 mbicr, vflre; | ||
51 | int i; | ||
52 | |||
53 | /* if there is no iov_data then there is no mailboxes to process */ | ||
54 | if (!ACCESS_ONCE(interface->iov_data)) | ||
55 | return 0; | ||
56 | |||
57 | rcu_read_lock(); | ||
58 | |||
59 | iov_data = interface->iov_data; | ||
60 | |||
61 | /* check again now that we are in the RCU block */ | ||
62 | if (!iov_data) | ||
63 | goto read_unlock; | ||
64 | |||
65 | if (!(fm10k_read_reg(hw, FM10K_EICR) & FM10K_EICR_VFLR)) | ||
66 | goto process_mbx; | ||
67 | |||
68 | /* read VFLRE to determine if any VFs have been reset */ | ||
69 | do { | ||
70 | vflre = fm10k_read_reg(hw, FM10K_PFVFLRE(0)); | ||
71 | vflre <<= 32; | ||
72 | vflre |= fm10k_read_reg(hw, FM10K_PFVFLRE(1)); | ||
73 | vflre = (vflre << 32) | (vflre >> 32); | ||
74 | vflre |= fm10k_read_reg(hw, FM10K_PFVFLRE(0)); | ||
75 | |||
76 | i = iov_data->num_vfs; | ||
77 | |||
78 | for (vflre <<= 64 - i; vflre && i--; vflre += vflre) { | ||
79 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | ||
80 | |||
81 | if (vflre >= 0) | ||
82 | continue; | ||
83 | |||
84 | hw->iov.ops.reset_resources(hw, vf_info); | ||
85 | vf_info->mbx.ops.connect(hw, &vf_info->mbx); | ||
86 | } | ||
87 | } while (i != iov_data->num_vfs); | ||
88 | |||
89 | process_mbx: | ||
90 | /* read MBICR to determine which VFs require attention */ | ||
91 | mbicr = fm10k_read_reg(hw, FM10K_MBICR(1)); | ||
92 | mbicr <<= 32; | ||
93 | mbicr |= fm10k_read_reg(hw, FM10K_MBICR(0)); | ||
94 | |||
95 | i = iov_data->next_vf_mbx ? : iov_data->num_vfs; | ||
96 | |||
97 | for (mbicr <<= 64 - i; i--; mbicr += mbicr) { | ||
98 | struct fm10k_mbx_info *mbx = &iov_data->vf_info[i].mbx; | ||
99 | |||
100 | if (mbicr >= 0) | ||
101 | continue; | ||
102 | |||
103 | if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) | ||
104 | break; | ||
105 | |||
106 | mbx->ops.process(hw, mbx); | ||
107 | } | ||
108 | |||
109 | if (i >= 0) { | ||
110 | iov_data->next_vf_mbx = i + 1; | ||
111 | } else if (iov_data->next_vf_mbx) { | ||
112 | iov_data->next_vf_mbx = 0; | ||
113 | goto process_mbx; | ||
114 | } | ||
115 | read_unlock: | ||
116 | rcu_read_unlock(); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | s32 fm10k_iov_mbx(struct fm10k_intfc *interface) | ||
122 | { | ||
123 | struct fm10k_hw *hw = &interface->hw; | ||
124 | struct fm10k_iov_data *iov_data; | ||
125 | int i; | ||
126 | |||
127 | /* if there is no iov_data then there is no mailboxes to process */ | ||
128 | if (!ACCESS_ONCE(interface->iov_data)) | ||
129 | return 0; | ||
130 | |||
131 | rcu_read_lock(); | ||
132 | |||
133 | iov_data = interface->iov_data; | ||
134 | |||
135 | /* check again now that we are in the RCU block */ | ||
136 | if (!iov_data) | ||
137 | goto read_unlock; | ||
138 | |||
139 | /* lock the mailbox for transmit and receive */ | ||
140 | fm10k_mbx_lock(interface); | ||
141 | |||
142 | process_mbx: | ||
143 | for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) { | ||
144 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | ||
145 | struct fm10k_mbx_info *mbx = &vf_info->mbx; | ||
146 | u16 glort = vf_info->glort; | ||
147 | |||
148 | /* verify port mapping is valid, if not reset port */ | ||
149 | if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort)) | ||
150 | hw->iov.ops.reset_lport(hw, vf_info); | ||
151 | |||
152 | /* reset VFs that have mailbox timed out */ | ||
153 | if (!mbx->timeout) { | ||
154 | hw->iov.ops.reset_resources(hw, vf_info); | ||
155 | mbx->ops.connect(hw, mbx); | ||
156 | } | ||
157 | |||
158 | /* no work pending, then just continue */ | ||
159 | if (mbx->ops.tx_complete(mbx) && !mbx->ops.rx_ready(mbx)) | ||
160 | continue; | ||
161 | |||
162 | /* guarantee we have free space in the SM mailbox */ | ||
163 | if (!hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) | ||
164 | break; | ||
165 | |||
166 | /* cleanup mailbox and process received messages */ | ||
167 | mbx->ops.process(hw, mbx); | ||
168 | } | ||
169 | |||
170 | if (i >= 0) { | ||
171 | iov_data->next_vf_mbx = i + 1; | ||
172 | } else if (iov_data->next_vf_mbx) { | ||
173 | iov_data->next_vf_mbx = 0; | ||
174 | goto process_mbx; | ||
175 | } | ||
176 | |||
177 | /* free the lock */ | ||
178 | fm10k_mbx_unlock(interface); | ||
179 | |||
180 | read_unlock: | ||
181 | rcu_read_unlock(); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | void fm10k_iov_suspend(struct pci_dev *pdev) | ||
187 | { | ||
188 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | ||
189 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
190 | struct fm10k_hw *hw = &interface->hw; | ||
191 | int num_vfs, i; | ||
192 | |||
193 | /* pull out num_vfs from iov_data */ | ||
194 | num_vfs = iov_data ? iov_data->num_vfs : 0; | ||
195 | |||
196 | /* shut down queue mapping for VFs */ | ||
197 | fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_vf_rss), | ||
198 | FM10K_DGLORTMAP_NONE); | ||
199 | |||
200 | /* Stop any active VFs and reset their resources */ | ||
201 | for (i = 0; i < num_vfs; i++) { | ||
202 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | ||
203 | |||
204 | hw->iov.ops.reset_resources(hw, vf_info); | ||
205 | hw->iov.ops.reset_lport(hw, vf_info); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | int fm10k_iov_resume(struct pci_dev *pdev) | ||
210 | { | ||
211 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | ||
212 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
213 | struct fm10k_dglort_cfg dglort = { 0 }; | ||
214 | struct fm10k_hw *hw = &interface->hw; | ||
215 | int num_vfs, i; | ||
216 | |||
217 | /* pull out num_vfs from iov_data */ | ||
218 | num_vfs = iov_data ? iov_data->num_vfs : 0; | ||
219 | |||
220 | /* return error if iov_data is not already populated */ | ||
221 | if (!iov_data) | ||
222 | return -ENOMEM; | ||
223 | |||
224 | /* allocate hardware resources for the VFs */ | ||
225 | hw->iov.ops.assign_resources(hw, num_vfs, num_vfs); | ||
226 | |||
227 | /* configure DGLORT mapping for RSS */ | ||
228 | dglort.glort = hw->mac.dglort_map & FM10K_DGLORTMAP_NONE; | ||
229 | dglort.idx = fm10k_dglort_vf_rss; | ||
230 | dglort.inner_rss = 1; | ||
231 | dglort.rss_l = fls(fm10k_queues_per_pool(hw) - 1); | ||
232 | dglort.queue_b = fm10k_vf_queue_index(hw, 0); | ||
233 | dglort.vsi_l = fls(hw->iov.total_vfs - 1); | ||
234 | dglort.vsi_b = 1; | ||
235 | |||
236 | hw->mac.ops.configure_dglort_map(hw, &dglort); | ||
237 | |||
238 | /* assign resources to the device */ | ||
239 | for (i = 0; i < num_vfs; i++) { | ||
240 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | ||
241 | |||
242 | /* allocate all but the last GLORT to the VFs */ | ||
243 | if (i == ((~hw->mac.dglort_map) >> FM10K_DGLORTMAP_MASK_SHIFT)) | ||
244 | break; | ||
245 | |||
246 | /* assign GLORT to VF, and restrict it to multicast */ | ||
247 | hw->iov.ops.set_lport(hw, vf_info, i, | ||
248 | FM10K_VF_FLAG_MULTI_CAPABLE); | ||
249 | |||
250 | /* assign our default vid to the VF following reset */ | ||
251 | vf_info->sw_vid = hw->mac.default_vid; | ||
252 | |||
253 | /* mailbox is disconnected so we don't send a message */ | ||
254 | hw->iov.ops.assign_default_mac_vlan(hw, vf_info); | ||
255 | |||
256 | /* now we are ready so we can connect */ | ||
257 | vf_info->mbx.ops.connect(hw, &vf_info->mbx); | ||
258 | } | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | s32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid) | ||
264 | { | ||
265 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
266 | struct fm10k_hw *hw = &interface->hw; | ||
267 | struct fm10k_vf_info *vf_info; | ||
268 | u16 vf_idx = (glort - hw->mac.dglort_map) & FM10K_DGLORTMAP_NONE; | ||
269 | |||
270 | /* no IOV support, not our message to process */ | ||
271 | if (!iov_data) | ||
272 | return FM10K_ERR_PARAM; | ||
273 | |||
274 | /* glort outside our range, not our message to process */ | ||
275 | if (vf_idx >= iov_data->num_vfs) | ||
276 | return FM10K_ERR_PARAM; | ||
277 | |||
278 | /* determine if an update has occured and if so notify the VF */ | ||
279 | vf_info = &iov_data->vf_info[vf_idx]; | ||
280 | if (vf_info->sw_vid != pvid) { | ||
281 | vf_info->sw_vid = pvid; | ||
282 | hw->iov.ops.assign_default_mac_vlan(hw, vf_info); | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static void fm10k_iov_free_data(struct pci_dev *pdev) | ||
289 | { | ||
290 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | ||
291 | |||
292 | if (!interface->iov_data) | ||
293 | return; | ||
294 | |||
295 | /* reclaim hardware resources */ | ||
296 | fm10k_iov_suspend(pdev); | ||
297 | |||
298 | /* drop iov_data from interface */ | ||
299 | kfree_rcu(interface->iov_data, rcu); | ||
300 | interface->iov_data = NULL; | ||
301 | } | ||
302 | |||
303 | static s32 fm10k_iov_alloc_data(struct pci_dev *pdev, int num_vfs) | ||
304 | { | ||
305 | struct fm10k_intfc *interface = pci_get_drvdata(pdev); | ||
306 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
307 | struct fm10k_hw *hw = &interface->hw; | ||
308 | size_t size; | ||
309 | int i, err; | ||
310 | |||
311 | /* return error if iov_data is already populated */ | ||
312 | if (iov_data) | ||
313 | return -EBUSY; | ||
314 | |||
315 | /* The PF should always be able to assign resources */ | ||
316 | if (!hw->iov.ops.assign_resources) | ||
317 | return -ENODEV; | ||
318 | |||
319 | /* nothing to do if no VFs are requested */ | ||
320 | if (!num_vfs) | ||
321 | return 0; | ||
322 | |||
323 | /* allocate memory for VF storage */ | ||
324 | size = offsetof(struct fm10k_iov_data, vf_info[num_vfs]); | ||
325 | iov_data = kzalloc(size, GFP_KERNEL); | ||
326 | if (!iov_data) | ||
327 | return -ENOMEM; | ||
328 | |||
329 | /* record number of VFs */ | ||
330 | iov_data->num_vfs = num_vfs; | ||
331 | |||
332 | /* loop through vf_info structures initializing each entry */ | ||
333 | for (i = 0; i < num_vfs; i++) { | ||
334 | struct fm10k_vf_info *vf_info = &iov_data->vf_info[i]; | ||
335 | |||
336 | /* Record VF VSI value */ | ||
337 | vf_info->vsi = i + 1; | ||
338 | vf_info->vf_idx = i; | ||
339 | |||
340 | /* initialize mailbox memory */ | ||
341 | err = fm10k_pfvf_mbx_init(hw, &vf_info->mbx, iov_mbx_data, i); | ||
342 | if (err) { | ||
343 | dev_err(&pdev->dev, | ||
344 | "Unable to initialize SR-IOV mailbox\n"); | ||
345 | kfree(iov_data); | ||
346 | return err; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | /* assign iov_data to interface */ | ||
351 | interface->iov_data = iov_data; | ||
352 | |||
353 | /* allocate hardware resources for the VFs */ | ||
354 | fm10k_iov_resume(pdev); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | void fm10k_iov_disable(struct pci_dev *pdev) | ||
360 | { | ||
361 | if (pci_num_vf(pdev) && pci_vfs_assigned(pdev)) | ||
362 | dev_err(&pdev->dev, | ||
363 | "Cannot disable SR-IOV while VFs are assigned\n"); | ||
364 | else | ||
365 | pci_disable_sriov(pdev); | ||
366 | |||
367 | fm10k_iov_free_data(pdev); | ||
368 | } | ||
369 | |||
370 | static void fm10k_disable_aer_comp_abort(struct pci_dev *pdev) | ||
371 | { | ||
372 | u32 err_sev; | ||
373 | int pos; | ||
374 | |||
375 | pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); | ||
376 | if (!pos) | ||
377 | return; | ||
378 | |||
379 | pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, &err_sev); | ||
380 | err_sev &= ~PCI_ERR_UNC_COMP_ABORT; | ||
381 | pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_SEVER, err_sev); | ||
382 | } | ||
383 | |||
384 | int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs) | ||
385 | { | ||
386 | int current_vfs = pci_num_vf(pdev); | ||
387 | int err = 0; | ||
388 | |||
389 | if (current_vfs && pci_vfs_assigned(pdev)) { | ||
390 | dev_err(&pdev->dev, | ||
391 | "Cannot modify SR-IOV while VFs are assigned\n"); | ||
392 | num_vfs = current_vfs; | ||
393 | } else { | ||
394 | pci_disable_sriov(pdev); | ||
395 | fm10k_iov_free_data(pdev); | ||
396 | } | ||
397 | |||
398 | /* allocate resources for the VFs */ | ||
399 | err = fm10k_iov_alloc_data(pdev, num_vfs); | ||
400 | if (err) | ||
401 | return err; | ||
402 | |||
403 | /* allocate VFs if not already allocated */ | ||
404 | if (num_vfs && (num_vfs != current_vfs)) { | ||
405 | /* Disable completer abort error reporting as | ||
406 | * the VFs can trigger this any time they read a queue | ||
407 | * that they don't own. | ||
408 | */ | ||
409 | fm10k_disable_aer_comp_abort(pdev); | ||
410 | |||
411 | err = pci_enable_sriov(pdev, num_vfs); | ||
412 | if (err) { | ||
413 | dev_err(&pdev->dev, | ||
414 | "Enable PCI SR-IOV failed: %d\n", err); | ||
415 | return err; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | return num_vfs; | ||
420 | } | ||
421 | |||
422 | int fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac) | ||
423 | { | ||
424 | struct fm10k_intfc *interface = netdev_priv(netdev); | ||
425 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
426 | struct fm10k_hw *hw = &interface->hw; | ||
427 | struct fm10k_vf_info *vf_info; | ||
428 | |||
429 | /* verify SR-IOV is active and that vf idx is valid */ | ||
430 | if (!iov_data || vf_idx >= iov_data->num_vfs) | ||
431 | return -EINVAL; | ||
432 | |||
433 | /* verify MAC addr is valid */ | ||
434 | if (!is_zero_ether_addr(mac) && !is_valid_ether_addr(mac)) | ||
435 | return -EINVAL; | ||
436 | |||
437 | /* record new MAC address */ | ||
438 | vf_info = &iov_data->vf_info[vf_idx]; | ||
439 | ether_addr_copy(vf_info->mac, mac); | ||
440 | |||
441 | /* assigning the MAC will send a mailbox message so lock is needed */ | ||
442 | fm10k_mbx_lock(interface); | ||
443 | |||
444 | /* assign MAC address to VF */ | ||
445 | hw->iov.ops.assign_default_mac_vlan(hw, vf_info); | ||
446 | |||
447 | fm10k_mbx_unlock(interface); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | int fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid, | ||
453 | u8 qos) | ||
454 | { | ||
455 | struct fm10k_intfc *interface = netdev_priv(netdev); | ||
456 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
457 | struct fm10k_hw *hw = &interface->hw; | ||
458 | struct fm10k_vf_info *vf_info; | ||
459 | |||
460 | /* verify SR-IOV is active and that vf idx is valid */ | ||
461 | if (!iov_data || vf_idx >= iov_data->num_vfs) | ||
462 | return -EINVAL; | ||
463 | |||
464 | /* QOS is unsupported and VLAN IDs accepted range 0-4094 */ | ||
465 | if (qos || (vid > (VLAN_VID_MASK - 1))) | ||
466 | return -EINVAL; | ||
467 | |||
468 | vf_info = &iov_data->vf_info[vf_idx]; | ||
469 | |||
470 | /* exit if there is nothing to do */ | ||
471 | if (vf_info->pf_vid == vid) | ||
472 | return 0; | ||
473 | |||
474 | /* record default VLAN ID for VF */ | ||
475 | vf_info->pf_vid = vid; | ||
476 | |||
477 | /* assigning the VLAN will send a mailbox message so lock is needed */ | ||
478 | fm10k_mbx_lock(interface); | ||
479 | |||
480 | /* Clear the VLAN table for the VF */ | ||
481 | hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, vf_info->vsi, false); | ||
482 | |||
483 | /* Update VF assignment and trigger reset */ | ||
484 | hw->iov.ops.assign_default_mac_vlan(hw, vf_info); | ||
485 | |||
486 | fm10k_mbx_unlock(interface); | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, int unused, | ||
492 | int rate) | ||
493 | { | ||
494 | struct fm10k_intfc *interface = netdev_priv(netdev); | ||
495 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
496 | struct fm10k_hw *hw = &interface->hw; | ||
497 | |||
498 | /* verify SR-IOV is active and that vf idx is valid */ | ||
499 | if (!iov_data || vf_idx >= iov_data->num_vfs) | ||
500 | return -EINVAL; | ||
501 | |||
502 | /* rate limit cannot be less than 10Mbs or greater than link speed */ | ||
503 | if (rate && ((rate < FM10K_VF_TC_MIN) || rate > FM10K_VF_TC_MAX)) | ||
504 | return -EINVAL; | ||
505 | |||
506 | /* store values */ | ||
507 | iov_data->vf_info[vf_idx].rate = rate; | ||
508 | |||
509 | /* update hardware configuration */ | ||
510 | hw->iov.ops.configure_tc(hw, vf_idx, rate); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | int fm10k_ndo_get_vf_config(struct net_device *netdev, | ||
516 | int vf_idx, struct ifla_vf_info *ivi) | ||
517 | { | ||
518 | struct fm10k_intfc *interface = netdev_priv(netdev); | ||
519 | struct fm10k_iov_data *iov_data = interface->iov_data; | ||
520 | struct fm10k_vf_info *vf_info; | ||
521 | |||
522 | /* verify SR-IOV is active and that vf idx is valid */ | ||
523 | if (!iov_data || vf_idx >= iov_data->num_vfs) | ||
524 | return -EINVAL; | ||
525 | |||
526 | vf_info = &iov_data->vf_info[vf_idx]; | ||
527 | |||
528 | ivi->vf = vf_idx; | ||
529 | ivi->max_tx_rate = vf_info->rate; | ||
530 | ivi->min_tx_rate = 0; | ||
531 | ether_addr_copy(ivi->mac, vf_info->mac); | ||
532 | ivi->vlan = vf_info->pf_vid; | ||
533 | ivi->qos = 0; | ||
534 | |||
535 | return 0; | ||
536 | } | ||
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index c0d6758ea16e..991abb25451e 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | |||
@@ -368,7 +368,21 @@ static void fm10k_request_glort_range(struct fm10k_intfc *interface) | |||
368 | if (hw->mac.dglort_map == FM10K_DGLORTMAP_NONE) | 368 | if (hw->mac.dglort_map == FM10K_DGLORTMAP_NONE) |
369 | return; | 369 | return; |
370 | 370 | ||
371 | interface->glort_count = mask + 1; | 371 | /* we support 3 possible GLORT configurations. |
372 | * 1: VFs consume all but the last 1 | ||
373 | * 2: VFs and PF split glorts with possible gap between | ||
374 | * 3: VFs allocated first 64, all others belong to PF | ||
375 | */ | ||
376 | if (mask <= hw->iov.total_vfs) { | ||
377 | interface->glort_count = 1; | ||
378 | interface->glort += mask; | ||
379 | } else if (mask < 64) { | ||
380 | interface->glort_count = (mask + 1) / 2; | ||
381 | interface->glort += interface->glort_count; | ||
382 | } else { | ||
383 | interface->glort_count = mask - 63; | ||
384 | interface->glort += 64; | ||
385 | } | ||
372 | } | 386 | } |
373 | 387 | ||
374 | /** | 388 | /** |
@@ -1325,6 +1339,10 @@ static const struct net_device_ops fm10k_netdev_ops = { | |||
1325 | .ndo_set_rx_mode = fm10k_set_rx_mode, | 1339 | .ndo_set_rx_mode = fm10k_set_rx_mode, |
1326 | .ndo_get_stats64 = fm10k_get_stats64, | 1340 | .ndo_get_stats64 = fm10k_get_stats64, |
1327 | .ndo_setup_tc = fm10k_setup_tc, | 1341 | .ndo_setup_tc = fm10k_setup_tc, |
1342 | .ndo_set_vf_mac = fm10k_ndo_set_vf_mac, | ||
1343 | .ndo_set_vf_vlan = fm10k_ndo_set_vf_vlan, | ||
1344 | .ndo_set_vf_rate = fm10k_ndo_set_vf_bw, | ||
1345 | .ndo_get_vf_config = fm10k_ndo_get_vf_config, | ||
1328 | .ndo_add_vxlan_port = fm10k_add_vxlan_port, | 1346 | .ndo_add_vxlan_port = fm10k_add_vxlan_port, |
1329 | .ndo_del_vxlan_port = fm10k_del_vxlan_port, | 1347 | .ndo_del_vxlan_port = fm10k_del_vxlan_port, |
1330 | .ndo_dfwd_add_station = fm10k_dfwd_add_station, | 1348 | .ndo_dfwd_add_station = fm10k_dfwd_add_station, |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 9cc4d627eb75..7935c1aad6d5 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c | |||
@@ -152,6 +152,8 @@ static void fm10k_reinit(struct fm10k_intfc *interface) | |||
152 | 152 | ||
153 | rtnl_lock(); | 153 | rtnl_lock(); |
154 | 154 | ||
155 | fm10k_iov_suspend(interface->pdev); | ||
156 | |||
155 | if (netif_running(netdev)) | 157 | if (netif_running(netdev)) |
156 | fm10k_close(netdev); | 158 | fm10k_close(netdev); |
157 | 159 | ||
@@ -171,6 +173,8 @@ static void fm10k_reinit(struct fm10k_intfc *interface) | |||
171 | if (netif_running(netdev)) | 173 | if (netif_running(netdev)) |
172 | fm10k_open(netdev); | 174 | fm10k_open(netdev); |
173 | 175 | ||
176 | fm10k_iov_resume(interface->pdev); | ||
177 | |||
174 | rtnl_unlock(); | 178 | rtnl_unlock(); |
175 | 179 | ||
176 | clear_bit(__FM10K_RESETTING, &interface->state); | 180 | clear_bit(__FM10K_RESETTING, &interface->state); |
@@ -260,6 +264,9 @@ static void fm10k_mbx_subtask(struct fm10k_intfc *interface) | |||
260 | { | 264 | { |
261 | /* process upstream mailbox and update device state */ | 265 | /* process upstream mailbox and update device state */ |
262 | fm10k_watchdog_update_host_state(interface); | 266 | fm10k_watchdog_update_host_state(interface); |
267 | |||
268 | /* process downstream mailboxes */ | ||
269 | fm10k_iov_mbx(interface); | ||
263 | } | 270 | } |
264 | 271 | ||
265 | /** | 272 | /** |
@@ -975,6 +982,7 @@ static irqreturn_t fm10k_msix_mbx_pf(int irq, void *data) | |||
975 | /* service mailboxes */ | 982 | /* service mailboxes */ |
976 | if (fm10k_mbx_trylock(interface)) { | 983 | if (fm10k_mbx_trylock(interface)) { |
977 | mbx->ops.process(hw, mbx); | 984 | mbx->ops.process(hw, mbx); |
985 | fm10k_iov_event(interface); | ||
978 | fm10k_mbx_unlock(interface); | 986 | fm10k_mbx_unlock(interface); |
979 | } | 987 | } |
980 | 988 | ||
@@ -1159,6 +1167,11 @@ static s32 fm10k_update_pvid(struct fm10k_hw *hw, u32 **results, | |||
1159 | 1167 | ||
1160 | interface = container_of(hw, struct fm10k_intfc, hw); | 1168 | interface = container_of(hw, struct fm10k_intfc, hw); |
1161 | 1169 | ||
1170 | /* check to see if this belongs to one of the VFs */ | ||
1171 | err = fm10k_iov_update_pvid(interface, glort, pvid); | ||
1172 | if (!err) | ||
1173 | return 0; | ||
1174 | |||
1162 | /* we need to reset if default VLAN was just updated */ | 1175 | /* we need to reset if default VLAN was just updated */ |
1163 | if (pvid != hw->mac.default_vid) | 1176 | if (pvid != hw->mac.default_vid) |
1164 | interface->flags |= FM10K_FLAG_RESET_REQUESTED; | 1177 | interface->flags |= FM10K_FLAG_RESET_REQUESTED; |
@@ -1477,6 +1490,10 @@ static int fm10k_sw_init(struct fm10k_intfc *interface, | |||
1477 | memcpy(&hw->mac.ops, fi->mac_ops, sizeof(hw->mac.ops)); | 1490 | memcpy(&hw->mac.ops, fi->mac_ops, sizeof(hw->mac.ops)); |
1478 | hw->mac.type = fi->mac; | 1491 | hw->mac.type = fi->mac; |
1479 | 1492 | ||
1493 | /* Setup IOV handlers */ | ||
1494 | if (fi->iov_ops) | ||
1495 | memcpy(&hw->iov.ops, fi->iov_ops, sizeof(hw->iov.ops)); | ||
1496 | |||
1480 | /* Set common capability flags and settings */ | 1497 | /* Set common capability flags and settings */ |
1481 | rss = min_t(int, FM10K_MAX_RSS_INDICES, num_online_cpus()); | 1498 | rss = min_t(int, FM10K_MAX_RSS_INDICES, num_online_cpus()); |
1482 | interface->ring_feature[RING_F_RSS].limit = rss; | 1499 | interface->ring_feature[RING_F_RSS].limit = rss; |
@@ -1509,6 +1526,9 @@ static int fm10k_sw_init(struct fm10k_intfc *interface, | |||
1509 | /* initialize hardware statistics */ | 1526 | /* initialize hardware statistics */ |
1510 | hw->mac.ops.update_hw_stats(hw, &interface->stats); | 1527 | hw->mac.ops.update_hw_stats(hw, &interface->stats); |
1511 | 1528 | ||
1529 | /* Set upper limit on IOV VFs that can be allocated */ | ||
1530 | pci_sriov_set_totalvfs(pdev, hw->iov.total_vfs); | ||
1531 | |||
1512 | /* Start with random Ethernet address */ | 1532 | /* Start with random Ethernet address */ |
1513 | eth_random_addr(hw->mac.addr); | 1533 | eth_random_addr(hw->mac.addr); |
1514 | 1534 | ||
@@ -1708,6 +1728,9 @@ static int fm10k_probe(struct pci_dev *pdev, | |||
1708 | /* print warning for non-optimal configurations */ | 1728 | /* print warning for non-optimal configurations */ |
1709 | fm10k_slot_warn(interface); | 1729 | fm10k_slot_warn(interface); |
1710 | 1730 | ||
1731 | /* enable SR-IOV after registering netdev to enforce PF/VF ordering */ | ||
1732 | fm10k_iov_configure(pdev, 0); | ||
1733 | |||
1711 | /* clear the service task disable bit to allow service task to start */ | 1734 | /* clear the service task disable bit to allow service task to start */ |
1712 | clear_bit(__FM10K_SERVICE_DISABLE, &interface->state); | 1735 | clear_bit(__FM10K_SERVICE_DISABLE, &interface->state); |
1713 | 1736 | ||
@@ -1751,6 +1774,9 @@ static void fm10k_remove(struct pci_dev *pdev) | |||
1751 | if (netdev->reg_state == NETREG_REGISTERED) | 1774 | if (netdev->reg_state == NETREG_REGISTERED) |
1752 | unregister_netdev(netdev); | 1775 | unregister_netdev(netdev); |
1753 | 1776 | ||
1777 | /* release VFs */ | ||
1778 | fm10k_iov_disable(pdev); | ||
1779 | |||
1754 | /* disable mailbox interrupt */ | 1780 | /* disable mailbox interrupt */ |
1755 | fm10k_mbx_free_irq(interface); | 1781 | fm10k_mbx_free_irq(interface); |
1756 | 1782 | ||
@@ -1827,6 +1853,9 @@ static int fm10k_resume(struct pci_dev *pdev) | |||
1827 | if (err) | 1853 | if (err) |
1828 | return err; | 1854 | return err; |
1829 | 1855 | ||
1856 | /* restore SR-IOV interface */ | ||
1857 | fm10k_iov_resume(pdev); | ||
1858 | |||
1830 | netif_device_attach(netdev); | 1859 | netif_device_attach(netdev); |
1831 | 1860 | ||
1832 | return 0; | 1861 | return 0; |
@@ -1848,6 +1877,8 @@ static int fm10k_suspend(struct pci_dev *pdev, pm_message_t state) | |||
1848 | 1877 | ||
1849 | netif_device_detach(netdev); | 1878 | netif_device_detach(netdev); |
1850 | 1879 | ||
1880 | fm10k_iov_suspend(pdev); | ||
1881 | |||
1851 | rtnl_lock(); | 1882 | rtnl_lock(); |
1852 | 1883 | ||
1853 | if (netif_running(netdev)) | 1884 | if (netif_running(netdev)) |
@@ -1989,6 +2020,7 @@ static struct pci_driver fm10k_driver = { | |||
1989 | .suspend = fm10k_suspend, | 2020 | .suspend = fm10k_suspend, |
1990 | .resume = fm10k_resume, | 2021 | .resume = fm10k_resume, |
1991 | #endif | 2022 | #endif |
2023 | .sriov_configure = fm10k_iov_configure, | ||
1992 | .err_handler = &fm10k_err_handler | 2024 | .err_handler = &fm10k_err_handler |
1993 | }; | 2025 | }; |
1994 | 2026 | ||