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); | |
43 | *delay = (u16)(val & I40E_PRTDCB_GENC_PFCLDA_MASK >> | |
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 | ||
181 | dcbxcfg = &hw->local_dcbx_config; | |
182 | ||
183 | /* Set up all the App TLVs if DCBx is negotiated */ | |
184 | for (i = 0; i < dcbxcfg->numapps; i++) { | |
185 | prio = dcbxcfg->app[i].priority; | |
186 | tc_map = (1 << dcbxcfg->etscfg.prioritytable[prio]); | |
187 | ||
188 | /* Add APP only if the TC is enabled for this VSI */ | |
189 | if (tc_map & vsi->tc_config.enabled_tc) { | |
190 | sapp.selector = dcbxcfg->app[i].selector; | |
191 | sapp.protocol = dcbxcfg->app[i].protocolid; | |
192 | sapp.priority = prio; | |
193 | dcb_ieee_setapp(dev, &sapp); | |
194 | } | |
195 | } | |
196 | ||
197 | /* Notify user-space of the changes */ | |
198 | dcbnl_ieee_notify(dev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0); | |
199 | } | |
200 | ||
201 | /** | |
202 | * i40e_dcbnl_vsi_del_app - Delete APP for given VSI | |
203 | * @vsi: the corresponding vsi | |
204 | * @app: APP to delete | |
205 | * | |
206 | * Delete given APP from the DCBNL APP table for given | |
207 | * VSI | |
208 | **/ | |
209 | static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi, | |
210 | struct i40e_ieee_app_priority_table *app) | |
211 | { | |
212 | struct net_device *dev = vsi->netdev; | |
213 | struct dcb_app sapp; | |
214 | ||
215 | if (!dev) | |
216 | return -EINVAL; | |
217 | ||
218 | sapp.selector = app->selector; | |
219 | sapp.protocol = app->protocolid; | |
220 | sapp.priority = app->priority; | |
221 | return dcb_ieee_delapp(dev, &sapp); | |
222 | } | |
223 | ||
224 | /** | |
225 | * i40e_dcbnl_del_app - Delete APP on all VSIs | |
226 | * @pf: the corresponding pf | |
227 | * @app: APP to delete | |
228 | * | |
229 | * Delete given APP from all the VSIs for given PF | |
230 | **/ | |
231 | static void i40e_dcbnl_del_app(struct i40e_pf *pf, | |
232 | struct i40e_ieee_app_priority_table *app) | |
233 | { | |
234 | int v, err; | |
505682cd | 235 | for (v = 0; v < pf->num_alloc_vsi; v++) { |
4e3b35b0 NP |
236 | if (pf->vsi[v] && pf->vsi[v]->netdev) { |
237 | err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app); | |
238 | if (err) | |
239 | dev_info(&pf->pdev->dev, "%s: Failed deleting app for VSI seid=%d err=%d sel=%d proto=0x%x prio=%d\n", | |
240 | __func__, pf->vsi[v]->seid, | |
241 | err, app->selector, | |
242 | app->protocolid, app->priority); | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
247 | /** | |
248 | * i40e_dcbnl_find_app - Search APP in given DCB config | |
249 | * @cfg: DCBX configuration data | |
250 | * @app: APP to search for | |
251 | * | |
252 | * Find given APP in the DCB configuration | |
253 | **/ | |
254 | static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg, | |
255 | struct i40e_ieee_app_priority_table *app) | |
256 | { | |
257 | int i; | |
258 | ||
259 | for (i = 0; i < cfg->numapps; i++) { | |
260 | if (app->selector == cfg->app[i].selector && | |
261 | app->protocolid == cfg->app[i].protocolid && | |
262 | app->priority == cfg->app[i].priority) | |
263 | return true; | |
264 | } | |
265 | ||
266 | return false; | |
267 | } | |
268 | ||
269 | /** | |
270 | * i40e_dcbnl_flush_apps - Delete all removed APPs | |
271 | * @pf: the corresponding pf | |
272 | * @new_cfg: new DCBX configuration data | |
273 | * | |
274 | * Find and delete all APPs that are not present in the passed | |
275 | * DCB configuration | |
276 | **/ | |
277 | void i40e_dcbnl_flush_apps(struct i40e_pf *pf, | |
278 | struct i40e_dcbx_config *new_cfg) | |
279 | { | |
280 | struct i40e_ieee_app_priority_table app; | |
281 | struct i40e_dcbx_config *dcbxcfg; | |
282 | struct i40e_hw *hw = &pf->hw; | |
283 | int i; | |
284 | ||
285 | dcbxcfg = &hw->local_dcbx_config; | |
286 | for (i = 0; i < dcbxcfg->numapps; i++) { | |
287 | app = dcbxcfg->app[i]; | |
288 | /* The APP is not available anymore delete it */ | |
289 | if (!i40e_dcbnl_find_app(new_cfg, &app)) | |
290 | i40e_dcbnl_del_app(pf, &app); | |
291 | } | |
292 | } | |
293 | ||
294 | /** | |
295 | * i40e_dcbnl_setup - DCBNL setup | |
296 | * @vsi: the corresponding vsi | |
297 | * | |
298 | * Set up DCBNL ops and initial APP TLVs | |
299 | **/ | |
300 | void i40e_dcbnl_setup(struct i40e_vsi *vsi) | |
301 | { | |
302 | struct net_device *dev = vsi->netdev; | |
303 | struct i40e_pf *pf = i40e_netdev_to_pf(dev); | |
304 | ||
305 | /* DCB not enabled */ | |
306 | if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) | |
307 | return; | |
308 | ||
309 | /* Do not setup DCB NL ops for MFP mode */ | |
310 | if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) | |
311 | dev->dcbnl_ops = &dcbnl_ops; | |
312 | ||
313 | /* Set initial IEEE DCB settings */ | |
314 | i40e_dcbnl_set_all(vsi); | |
315 | } | |
316 | #endif /* CONFIG_I40E_DCB */ |