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