i40evf: support RSS
[dpdk.git] / lib / librte_pmd_i40e / i40e / i40e_dcb.c
1 /*******************************************************************************
2
3 Copyright (c) 2013 - 2014, Intel Corporation
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9  1. Redistributions of source code must retain the above copyright notice,
10     this list of conditions and the following disclaimer.
11
12  2. Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in the
14     documentation and/or other materials provided with the distribution.
15
16  3. Neither the name of the Intel Corporation nor the names of its
17     contributors may be used to endorse or promote products derived from
18     this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31
32 ***************************************************************************/
33
34 #include "i40e_adminq.h"
35 #include "i40e_prototype.h"
36 #include "i40e_dcb.h"
37
38 /**
39  * i40e_get_dcbx_status
40  * @hw: pointer to the hw struct
41  * @status: Embedded DCBX Engine Status
42  *
43  * Get the DCBX status from the Firmware
44  **/
45 enum i40e_status_code i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
46 {
47         u32 reg;
48
49         if (!status)
50                 return I40E_ERR_PARAM;
51
52         reg = rd32(hw, I40E_PRTDCB_GENS);
53         *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
54                         I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
55
56         return I40E_SUCCESS;
57 }
58
59 /**
60  * i40e_parse_ieee_etscfg_tlv
61  * @tlv: IEEE 802.1Qaz ETS CFG TLV
62  * @dcbcfg: Local store to update ETS CFG data
63  *
64  * Parses IEEE 802.1Qaz ETS CFG TLV
65  **/
66 static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
67                                        struct i40e_dcbx_config *dcbcfg)
68 {
69         struct i40e_ieee_ets_config *etscfg;
70         u8 *buf = tlv->tlvinfo;
71         u16 offset = 0;
72         u8 priority;
73         int i;
74
75         /* First Octet post subtype
76          * --------------------------
77          * |will-|CBS  | Re-  | Max |
78          * |ing  |     |served| TCs |
79          * --------------------------
80          * |1bit | 1bit|3 bits|3bits|
81          */
82         etscfg = &dcbcfg->etscfg;
83         etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
84                                I40E_IEEE_ETS_WILLING_SHIFT);
85         etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
86                            I40E_IEEE_ETS_CBS_SHIFT);
87         etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
88                               I40E_IEEE_ETS_MAXTC_SHIFT);
89
90         /* Move offset to Priority Assignment Table */
91         offset++;
92
93         /* Priority Assignment Table (4 octets)
94          * Octets:|    1    |    2    |    3    |    4    |
95          *        -----------------------------------------
96          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
97          *        -----------------------------------------
98          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
99          *        -----------------------------------------
100          */
101         for (i = 0; i < 4; i++) {
102                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
103                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
104                 etscfg->prioritytable[i * 2] =  priority;
105                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
106                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
107                 etscfg->prioritytable[i * 2 + 1] = priority;
108                 offset++;
109         }
110
111         /* TC Bandwidth Table (8 octets)
112          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
113          *        ---------------------------------
114          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
115          *        ---------------------------------
116          */
117         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
118                 etscfg->tcbwtable[i] = buf[offset++];
119
120         /* TSA Assignment Table (8 octets)
121          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
122          *        ---------------------------------
123          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
124          *        ---------------------------------
125          */
126         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
127                 etscfg->tsatable[i] = buf[offset++];
128 }
129
130 /**
131  * i40e_parse_ieee_etsrec_tlv
132  * @tlv: IEEE 802.1Qaz ETS REC TLV
133  * @dcbcfg: Local store to update ETS REC data
134  *
135  * Parses IEEE 802.1Qaz ETS REC TLV
136  **/
137 static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
138                                        struct i40e_dcbx_config *dcbcfg)
139 {
140         u8 *buf = tlv->tlvinfo;
141         u16 offset = 0;
142         u8 priority;
143         int i;
144
145         /* Move offset to priority table */
146         offset++;
147
148         /* Priority Assignment Table (4 octets)
149          * Octets:|    1    |    2    |    3    |    4    |
150          *        -----------------------------------------
151          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
152          *        -----------------------------------------
153          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
154          *        -----------------------------------------
155          */
156         for (i = 0; i < 4; i++) {
157                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
158                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
159                 dcbcfg->etsrec.prioritytable[i*2] =  priority;
160                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
161                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
162                 dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
163                 offset++;
164         }
165
166         /* TC Bandwidth Table (8 octets)
167          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
168          *        ---------------------------------
169          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
170          *        ---------------------------------
171          */
172         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
173                 dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
174
175         /* TSA Assignment Table (8 octets)
176          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
177          *        ---------------------------------
178          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
179          *        ---------------------------------
180          */
181         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
182                 dcbcfg->etsrec.tsatable[i] = buf[offset++];
183 }
184
185 /**
186  * i40e_parse_ieee_pfccfg_tlv
187  * @tlv: IEEE 802.1Qaz PFC CFG TLV
188  * @dcbcfg: Local store to update PFC CFG data
189  *
190  * Parses IEEE 802.1Qaz PFC CFG TLV
191  **/
192 static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
193                                        struct i40e_dcbx_config *dcbcfg)
194 {
195         u8 *buf = tlv->tlvinfo;
196
197         /* ----------------------------------------
198          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
199          * |ing  |     |served| cap |              |
200          * -----------------------------------------
201          * |1bit | 1bit|2 bits|4bits| 1 octet      |
202          */
203         dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
204                                    I40E_IEEE_PFC_WILLING_SHIFT);
205         dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
206                                I40E_IEEE_PFC_MBC_SHIFT);
207         dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
208                                   I40E_IEEE_PFC_CAP_SHIFT);
209         dcbcfg->pfc.pfcenable = buf[1];
210 }
211
212 /**
213  * i40e_parse_ieee_app_tlv
214  * @tlv: IEEE 802.1Qaz APP TLV
215  * @dcbcfg: Local store to update APP PRIO data
216  *
217  * Parses IEEE 802.1Qaz APP PRIO TLV
218  **/
219 static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
220                                     struct i40e_dcbx_config *dcbcfg)
221 {
222         u16 typelength;
223         u16 offset = 0;
224         u16 length;
225         int i = 0;
226         u8 *buf;
227
228         typelength = I40E_NTOHS(tlv->typelength);
229         length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
230                        I40E_LLDP_TLV_LEN_SHIFT);
231         buf = tlv->tlvinfo;
232
233         /* The App priority table starts 5 octets after TLV header */
234         length -= (sizeof(tlv->ouisubtype) + 1);
235
236         /* Move offset to App Priority Table */
237         offset++;
238
239         /* Application Priority Table (3 octets)
240          * Octets:|         1          |    2    |    3    |
241          *        -----------------------------------------
242          *        |Priority|Rsrvd| Sel |    Protocol ID    |
243          *        -----------------------------------------
244          *   Bits:|23    21|20 19|18 16|15                0|
245          *        -----------------------------------------
246          */
247         while (offset < length) {
248                 dcbcfg->app[i].priority = (u8)((buf[offset] &
249                                                 I40E_IEEE_APP_PRIO_MASK) >>
250                                                I40E_IEEE_APP_PRIO_SHIFT);
251                 dcbcfg->app[i].selector = (u8)((buf[offset] &
252                                                 I40E_IEEE_APP_SEL_MASK) >>
253                                                I40E_IEEE_APP_SEL_SHIFT);
254                 dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
255                                              buf[offset + 2];
256                 /* Move to next app */
257                 offset += 3;
258                 i++;
259                 if (i >= I40E_DCBX_MAX_APPS)
260                         break;
261         }
262
263         dcbcfg->numapps = i;
264 }
265
266 /**
267  * i40e_parse_ieee_etsrec_tlv
268  * @tlv: IEEE 802.1Qaz TLV
269  * @dcbcfg: Local store to update ETS REC data
270  *
271  * Get the TLV subtype and send it to parsing function
272  * based on the subtype value
273  **/
274 static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
275                                 struct i40e_dcbx_config *dcbcfg)
276 {
277         u32 ouisubtype;
278         u8 subtype;
279
280         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
281         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
282                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
283         switch (subtype) {
284         case I40E_IEEE_SUBTYPE_ETS_CFG:
285                 i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
286                 break;
287         case I40E_IEEE_SUBTYPE_ETS_REC:
288                 i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
289                 break;
290         case I40E_IEEE_SUBTYPE_PFC_CFG:
291                 i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
292                 break;
293         case I40E_IEEE_SUBTYPE_APP_PRI:
294                 i40e_parse_ieee_app_tlv(tlv, dcbcfg);
295                 break;
296         default:
297                 break;
298         }
299 }
300
301 /**
302  * i40e_parse_org_tlv
303  * @tlv: Organization specific TLV
304  * @dcbcfg: Local store to update ETS REC data
305  *
306  * Currently only IEEE 802.1Qaz TLV is supported, all others
307  * will be returned
308  **/
309 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
310                                struct i40e_dcbx_config *dcbcfg)
311 {
312         u32 ouisubtype;
313         u32 oui;
314
315         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
316         oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
317                     I40E_LLDP_TLV_OUI_SHIFT);
318         switch (oui) {
319         case I40E_IEEE_8021QAZ_OUI:
320                 i40e_parse_ieee_tlv(tlv, dcbcfg);
321                 break;
322         default:
323                 break;
324         }
325 }
326
327 /**
328  * i40e_lldp_to_dcb_config
329  * @lldpmib: LLDPDU to be parsed
330  * @dcbcfg: store for LLDPDU data
331  *
332  * Parse DCB configuration from the LLDPDU
333  **/
334 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
335                                     struct i40e_dcbx_config *dcbcfg)
336 {
337         enum i40e_status_code ret = I40E_SUCCESS;
338         struct i40e_lldp_org_tlv *tlv;
339         u16 type;
340         u16 length;
341         u16 typelength;
342         u16 offset = 0;
343
344         if (!lldpmib || !dcbcfg)
345                 return I40E_ERR_PARAM;
346
347         /* set to the start of LLDPDU */
348         lldpmib += I40E_LLDP_MIB_HLEN;
349         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
350         while (1) {
351                 typelength = I40E_NTOHS(tlv->typelength);
352                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
353                              I40E_LLDP_TLV_TYPE_SHIFT);
354                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
355                                I40E_LLDP_TLV_LEN_SHIFT);
356                 offset += sizeof(typelength) + length;
357
358                 /* END TLV or beyond LLDPDU size */
359                 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
360                         break;
361
362                 switch (type) {
363                 case I40E_TLV_TYPE_ORG:
364                         i40e_parse_org_tlv(tlv, dcbcfg);
365                         break;
366                 default:
367                         break;
368                 }
369
370                 /* Move to next TLV */
371                 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
372                                                     sizeof(tlv->typelength) +
373                                                     length);
374         }
375
376         return ret;
377 }
378
379 /**
380  * i40e_aq_get_dcb_config
381  * @hw: pointer to the hw struct
382  * @mib_type: mib type for the query
383  * @bridgetype: bridge type for the query (remote)
384  * @dcbcfg: store for LLDPDU data
385  *
386  * Query DCB configuration from the Firmware
387  **/
388 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
389                                    u8 bridgetype,
390                                    struct i40e_dcbx_config *dcbcfg)
391 {
392         enum i40e_status_code ret = I40E_SUCCESS;
393         struct i40e_virt_mem mem;
394         u8 *lldpmib;
395
396         /* Allocate the LLDPDU */
397         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
398         if (ret)
399                 return ret;
400
401         lldpmib = (u8 *)mem.va;
402         ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
403                                    (void *)lldpmib, I40E_LLDPDU_SIZE,
404                                    NULL, NULL, NULL);
405         if (ret)
406                 goto free_mem;
407
408         /* Parse LLDP MIB to get dcb configuration */
409         ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
410
411 free_mem:
412         i40e_free_virt_mem(hw, &mem);
413         return ret;
414 }
415
416 /**
417  * i40e_get_dcb_config
418  * @hw: pointer to the hw struct
419  *
420  * Get DCB configuration from the Firmware
421  **/
422 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
423 {
424         enum i40e_status_code ret = I40E_SUCCESS;
425
426         /* Get Local DCB Config */
427         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
428                                      &hw->local_dcbx_config);
429         if (ret)
430                 goto out;
431
432         /* Get Remote DCB Config */
433         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
434                                      I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
435                                      &hw->remote_dcbx_config);
436 out:
437         return ret;
438 }
439
440 /**
441  * i40e_init_dcb
442  * @hw: pointer to the hw struct
443  *
444  * Update DCB configuration from the Firmware
445  **/
446 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
447 {
448         enum i40e_status_code ret = I40E_SUCCESS;
449
450         if (!hw->func_caps.dcb)
451                 return ret;
452
453         /* Get DCBX status */
454         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
455         if (ret)
456                 return ret;
457
458         /* Check the DCBX Status */
459         switch (hw->dcbx_status) {
460         case I40E_DCBX_STATUS_DONE:
461         case I40E_DCBX_STATUS_IN_PROGRESS:
462                 /* Get current DCBX configuration */
463                 ret = i40e_get_dcb_config(hw);
464                 break;
465         case I40E_DCBX_STATUS_DISABLED:
466                 return ret;
467         case I40E_DCBX_STATUS_NOT_STARTED:
468         case I40E_DCBX_STATUS_MULTIPLE_PEERS:
469         default:
470                 break;
471         }
472
473         /* Configure the LLDP MIB change event */
474         ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
475         if (ret)
476                 return ret;
477
478         return ret;
479 }