]>
Commit | Line | Data |
---|---|---|
ae06c70b | 1 | // SPDX-License-Identifier: GPL-2.0 |
4e3b35b0 NP |
2 | /******************************************************************************* |
3 | * | |
4 | * Intel Ethernet Controller XL710 Family Linux Driver | |
5 | * Copyright(c) 2013 - 2014 Intel Corporation. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms and conditions of the GNU General Public License, | |
9 | * version 2, as published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along | |
17 | * with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | * | |
19 | * The full GNU General Public License is included in this distribution in | |
20 | * the file called "COPYING". | |
21 | * | |
22 | * Contact Information: | |
23 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | |
24 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
25 | * | |
26 | ******************************************************************************/ | |
27 | ||
28 | #ifdef CONFIG_I40E_DCB | |
29 | #include "i40e.h" | |
30 | #include <net/dcbnl.h> | |
31 | ||
32 | /** | |
33 | * i40e_get_pfc_delay - retrieve PFC Link Delay | |
34 | * @hw: pointer to hardware struct | |
35 | * @delay: holds the PFC Link delay value | |
36 | * | |
37 | * Returns PFC Link Delay from the PRTDCB_GENC.PFCLDA | |
38 | **/ | |
39 | static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay) | |
40 | { | |
41 | u32 val; | |
42 | ||
43 | val = rd32(hw, I40E_PRTDCB_GENC); | |
de78fc5a | 44 | *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >> |
4e3b35b0 NP |
45 | I40E_PRTDCB_GENC_PFCLDA_SHIFT); |
46 | } | |
47 | ||
48 | /** | |
49 | * i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration | |
50 | * @netdev: the corresponding netdev | |
51 | * @ets: structure to hold the ETS information | |
52 | * | |
53 | * Returns local IEEE ETS configuration | |
54 | **/ | |
55 | static int i40e_dcbnl_ieee_getets(struct net_device *dev, | |
56 | struct ieee_ets *ets) | |
57 | { | |
58 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); | |
59 | struct i40e_dcbx_config *dcbxcfg; | |
60 | struct i40e_hw *hw = &pf->hw; | |
61 | ||
62 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) | |
63 | return -EINVAL; | |
64 | ||
65 | dcbxcfg = &hw->local_dcbx_config; | |
66 | ets->willing = dcbxcfg->etscfg.willing; | |
67 | ets->ets_cap = dcbxcfg->etscfg.maxtcs; | |
68 | ets->cbs = dcbxcfg->etscfg.cbs; | |
69 | memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable, | |
70 | sizeof(ets->tc_tx_bw)); | |
71 | memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable, | |
72 | sizeof(ets->tc_rx_bw)); | |
73 | memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable, | |
74 | sizeof(ets->tc_tsa)); | |
75 | memcpy(ets->prio_tc, dcbxcfg->etscfg.prioritytable, | |
76 | sizeof(ets->prio_tc)); | |
77 | memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable, | |
78 | sizeof(ets->tc_reco_bw)); | |
79 | memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable, | |
80 | sizeof(ets->tc_reco_tsa)); | |
81 | memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prioritytable, | |
82 | sizeof(ets->reco_prio_tc)); | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | /** | |
88 | * i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration | |
89 | * @netdev: the corresponding netdev | |
90 | * @ets: structure to hold the PFC information | |
91 | * | |
92 | * Returns local IEEE PFC configuration | |
93 | **/ | |
94 | static int i40e_dcbnl_ieee_getpfc(struct net_device *dev, | |
95 | struct ieee_pfc *pfc) | |
96 | { | |
97 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); | |
98 | struct i40e_dcbx_config *dcbxcfg; | |
99 | struct i40e_hw *hw = &pf->hw; | |
100 | int i; | |
101 | ||
102 | if (!(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) | |
103 | return -EINVAL; | |
104 | ||
105 | dcbxcfg = &hw->local_dcbx_config; | |
106 | pfc->pfc_cap = dcbxcfg->pfc.pfccap; | |
107 | pfc->pfc_en = dcbxcfg->pfc.pfcenable; | |
108 | pfc->mbc = dcbxcfg->pfc.mbc; | |
109 | i40e_get_pfc_delay(hw, &pfc->delay); | |
110 | ||
111 | /* Get Requests/Indicatiosn */ | |
112 | for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { | |
113 | pfc->requests[i] = pf->stats.priority_xoff_tx[i]; | |
114 | pfc->indications[i] = pf->stats.priority_xoff_rx[i]; | |
115 | } | |
116 | ||
117 | return 0; | |
118 | } | |
119 | ||
120 | /** | |
121 | * i40e_dcbnl_getdcbx - retrieve current DCBx capability | |
122 | * @netdev: the corresponding netdev | |
123 | * | |
124 | * Returns DCBx capability features | |
125 | **/ | |
126 | static u8 i40e_dcbnl_getdcbx(struct net_device *dev) | |
127 | { | |
128 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); | |
129 | ||
130 | return pf->dcbx_cap; | |
131 | } | |
132 | ||
133 | /** | |
134 | * i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx | |
135 | * @netdev: the corresponding netdev | |
136 | * | |
137 | * Returns the SAN MAC address used for LLDP exchange | |
138 | **/ | |
139 | static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev, | |
140 | u8 *perm_addr) | |
141 | { | |
142 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); | |
143 | int i, j; | |
144 | ||
145 | memset(perm_addr, 0xff, MAX_ADDR_LEN); | |
146 | ||
147 | for (i = 0; i < dev->addr_len; i++) | |
148 | perm_addr[i] = pf->hw.mac.perm_addr[i]; | |
149 | ||
150 | for (j = 0; j < dev->addr_len; j++, i++) | |
151 | perm_addr[i] = pf->hw.mac.san_addr[j]; | |
152 | } | |
153 | ||
154 | static const struct dcbnl_rtnl_ops dcbnl_ops = { | |
155 | .ieee_getets = i40e_dcbnl_ieee_getets, | |
156 | .ieee_getpfc = i40e_dcbnl_ieee_getpfc, | |
157 | .getdcbx = i40e_dcbnl_getdcbx, | |
158 | .getpermhwaddr = i40e_dcbnl_get_perm_hw_addr, | |
159 | }; | |
160 | ||
161 | /** | |
162 | * i40e_dcbnl_set_all - set all the apps and ieee data from DCBx config | |
163 | * @vsi: the corresponding vsi | |
164 | * | |
165 | * Set up all the IEEE APPs in the DCBNL App Table and generate event for | |
166 | * other settings | |
167 | **/ | |
168 | void i40e_dcbnl_set_all(struct i40e_vsi *vsi) | |
169 | { | |
170 | struct net_device *dev = vsi->netdev; | |
171 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); | |
172 | struct i40e_dcbx_config *dcbxcfg; | |
173 | struct i40e_hw *hw = &pf->hw; | |
174 | struct dcb_app sapp; | |
175 | u8 prio, tc_map; | |
176 | int i; | |
177 | ||
178 | /* DCB not enabled */ | |
179 | if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) | |
180 | return; | |
181 | ||
c142b1dc NP |
182 | /* MFP mode but not an iSCSI PF so return */ |
183 | if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi)) | |
184 | return; | |
185 | ||
4e3b35b0 NP |
186 | dcbxcfg = &hw->local_dcbx_config; |
187 | ||
188 | /* Set up all the App TLVs if DCBx is negotiated */ | |
189 | for (i = 0; i < dcbxcfg->numapps; i++) { | |
190 | prio = dcbxcfg->app[i].priority; | |
41a1d04b | 191 | tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]); |
4e3b35b0 NP |
192 | |
193 | /* Add APP only if the TC is enabled for this VSI */ | |
194 | if (tc_map & vsi->tc_config.enabled_tc) { | |
195 | sapp.selector = dcbxcfg->app[i].selector; | |
196 | sapp.protocol = dcbxcfg->app[i].protocolid; | |
197 | sapp.priority = prio; | |
198 | dcb_ieee_setapp(dev, &sapp); | |
199 | } | |
200 | } | |
201 | ||
202 | /* Notify user-space of the changes */ | |
203 | dcbnl_ieee_notify(dev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0); | |
204 | } | |
205 | ||
206 | /** | |
207 | * i40e_dcbnl_vsi_del_app - Delete APP for given VSI | |
208 | * @vsi: the corresponding vsi | |
209 | * @app: APP to delete | |
210 | * | |
211 | * Delete given APP from the DCBNL APP table for given | |
212 | * VSI | |
213 | **/ | |
214 | static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi, | |
9fa61dd2 | 215 | struct i40e_dcb_app_priority_table *app) |
4e3b35b0 NP |
216 | { |
217 | struct net_device *dev = vsi->netdev; | |
218 | struct dcb_app sapp; | |
219 | ||
220 | if (!dev) | |
221 | return -EINVAL; | |
222 | ||
223 | sapp.selector = app->selector; | |
224 | sapp.protocol = app->protocolid; | |
225 | sapp.priority = app->priority; | |
226 | return dcb_ieee_delapp(dev, &sapp); | |
227 | } | |
228 | ||
229 | /** | |
230 | * i40e_dcbnl_del_app - Delete APP on all VSIs | |
b40c82e6 | 231 | * @pf: the corresponding PF |
4e3b35b0 NP |
232 | * @app: APP to delete |
233 | * | |
234 | * Delete given APP from all the VSIs for given PF | |
235 | **/ | |
236 | static void i40e_dcbnl_del_app(struct i40e_pf *pf, | |
9fa61dd2 | 237 | struct i40e_dcb_app_priority_table *app) |
4e3b35b0 NP |
238 | { |
239 | int v, err; | |
6995b36c | 240 | |
505682cd | 241 | for (v = 0; v < pf->num_alloc_vsi; v++) { |
4e3b35b0 NP |
242 | if (pf->vsi[v] && pf->vsi[v]->netdev) { |
243 | err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app); | |
8279e495 NP |
244 | dev_dbg(&pf->pdev->dev, "Deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n", |
245 | pf->vsi[v]->seid, err, app->selector, | |
246 | app->protocolid, app->priority); | |
4e3b35b0 NP |
247 | } |
248 | } | |
249 | } | |
250 | ||
251 | /** | |
252 | * i40e_dcbnl_find_app - Search APP in given DCB config | |
253 | * @cfg: DCBX configuration data | |
254 | * @app: APP to search for | |
255 | * | |
256 | * Find given APP in the DCB configuration | |
257 | **/ | |
258 | static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg, | |
9fa61dd2 | 259 | struct i40e_dcb_app_priority_table *app) |
4e3b35b0 NP |
260 | { |
261 | int i; | |
262 | ||
263 | for (i = 0; i < cfg->numapps; i++) { | |
264 | if (app->selector == cfg->app[i].selector && | |
265 | app->protocolid == cfg->app[i].protocolid && | |
266 | app->priority == cfg->app[i].priority) | |
267 | return true; | |
268 | } | |
269 | ||
270 | return false; | |
271 | } | |
272 | ||
273 | /** | |
274 | * i40e_dcbnl_flush_apps - Delete all removed APPs | |
b40c82e6 | 275 | * @pf: the corresponding PF |
750fcbcf | 276 | * @old_cfg: old DCBX configuration data |
4e3b35b0 NP |
277 | * @new_cfg: new DCBX configuration data |
278 | * | |
279 | * Find and delete all APPs that are not present in the passed | |
280 | * DCB configuration | |
281 | **/ | |
282 | void i40e_dcbnl_flush_apps(struct i40e_pf *pf, | |
750fcbcf | 283 | struct i40e_dcbx_config *old_cfg, |
4e3b35b0 NP |
284 | struct i40e_dcbx_config *new_cfg) |
285 | { | |
9fa61dd2 | 286 | struct i40e_dcb_app_priority_table app; |
4e3b35b0 NP |
287 | int i; |
288 | ||
c142b1dc NP |
289 | /* MFP mode but not an iSCSI PF so return */ |
290 | if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi)) | |
291 | return; | |
292 | ||
750fcbcf NP |
293 | for (i = 0; i < old_cfg->numapps; i++) { |
294 | app = old_cfg->app[i]; | |
4e3b35b0 NP |
295 | /* The APP is not available anymore delete it */ |
296 | if (!i40e_dcbnl_find_app(new_cfg, &app)) | |
297 | i40e_dcbnl_del_app(pf, &app); | |
298 | } | |
299 | } | |
300 | ||
301 | /** | |
302 | * i40e_dcbnl_setup - DCBNL setup | |
303 | * @vsi: the corresponding vsi | |
304 | * | |
305 | * Set up DCBNL ops and initial APP TLVs | |
306 | **/ | |
307 | void i40e_dcbnl_setup(struct i40e_vsi *vsi) | |
308 | { | |
309 | struct net_device *dev = vsi->netdev; | |
310 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); | |
311 | ||
4d9b6043 NP |
312 | /* Not DCB capable */ |
313 | if (!(pf->flags & I40E_FLAG_DCB_CAPABLE)) | |
4e3b35b0 NP |
314 | return; |
315 | ||
15d504b9 | 316 | dev->dcbnl_ops = &dcbnl_ops; |
4e3b35b0 NP |
317 | |
318 | /* Set initial IEEE DCB settings */ | |
319 | i40e_dcbnl_set_all(vsi); | |
320 | } | |
321 | #endif /* CONFIG_I40E_DCB */ |