net/ice/base: implement LLDP persistent settings
[dpdk.git] / drivers / net / ice / base / ice_dcb.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2001-2019
3  */
4
5 #include "ice_common.h"
6 #include "ice_sched.h"
7 #include "ice_dcb.h"
8
9 /**
10  * ice_aq_get_lldp_mib
11  * @hw: pointer to the HW struct
12  * @bridge_type: type of bridge requested
13  * @mib_type: Local, Remote or both Local and Remote MIBs
14  * @buf: pointer to the caller-supplied buffer to store the MIB block
15  * @buf_size: size of the buffer (in bytes)
16  * @local_len: length of the returned Local LLDP MIB
17  * @remote_len: length of the returned Remote LLDP MIB
18  * @cd: pointer to command details structure or NULL
19  *
20  * Requests the complete LLDP MIB (entire packet). (0x0A00)
21  */
22 enum ice_status
23 ice_aq_get_lldp_mib(struct ice_hw *hw, u8 bridge_type, u8 mib_type, void *buf,
24                     u16 buf_size, u16 *local_len, u16 *remote_len,
25                     struct ice_sq_cd *cd)
26 {
27         struct ice_aqc_lldp_get_mib *cmd;
28         struct ice_aq_desc desc;
29         enum ice_status status;
30
31         cmd = &desc.params.lldp_get_mib;
32
33         if (buf_size == 0 || !buf)
34                 return ICE_ERR_PARAM;
35
36         ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_get_mib);
37
38         cmd->type = mib_type & ICE_AQ_LLDP_MIB_TYPE_M;
39         cmd->type |= (bridge_type << ICE_AQ_LLDP_BRID_TYPE_S) &
40                 ICE_AQ_LLDP_BRID_TYPE_M;
41
42         desc.datalen = CPU_TO_LE16(buf_size);
43
44         status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
45         if (!status) {
46                 if (local_len)
47                         *local_len = LE16_TO_CPU(cmd->local_len);
48                 if (remote_len)
49                         *remote_len = LE16_TO_CPU(cmd->remote_len);
50         }
51
52         return status;
53 }
54
55 /**
56  * ice_aq_cfg_lldp_mib_change
57  * @hw: pointer to the HW struct
58  * @ena_update: Enable or Disable event posting
59  * @cd: pointer to command details structure or NULL
60  *
61  * Enable or Disable posting of an event on ARQ when LLDP MIB
62  * associated with the interface changes (0x0A01)
63  */
64 enum ice_status
65 ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update,
66                            struct ice_sq_cd *cd)
67 {
68         struct ice_aqc_lldp_set_mib_change *cmd;
69         struct ice_aq_desc desc;
70
71         cmd = &desc.params.lldp_set_event;
72
73         ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_mib_change);
74
75         if (!ena_update)
76                 cmd->command |= ICE_AQ_LLDP_MIB_UPDATE_DIS;
77
78         return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
79 }
80
81 /**
82  * ice_aq_stop_lldp
83  * @hw: pointer to the HW struct
84  * @shutdown_lldp_agent: True if LLDP Agent needs to be Shutdown
85  *                       False if LLDP Agent needs to be Stopped
86  * @persist: True if Stop/Shutdown of LLDP Agent needs to be persistent across
87  *           reboots
88  * @cd: pointer to command details structure or NULL
89  *
90  * Stop or Shutdown the embedded LLDP Agent (0x0A05)
91  */
92 enum ice_status
93 ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist,
94                  struct ice_sq_cd *cd)
95 {
96         struct ice_aqc_lldp_stop *cmd;
97         struct ice_aq_desc desc;
98
99         cmd = &desc.params.lldp_stop;
100
101         ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_stop);
102
103         if (shutdown_lldp_agent)
104                 cmd->command |= ICE_AQ_LLDP_AGENT_SHUTDOWN;
105
106         if (persist)
107                 cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_DIS;
108
109         return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
110 }
111
112 /**
113  * ice_aq_start_lldp
114  * @hw: pointer to the HW struct
115  * @persist: True if Start of LLDP Agent needs to be persistent across reboots
116  * @cd: pointer to command details structure or NULL
117  *
118  * Start the embedded LLDP Agent on all ports. (0x0A06)
119  */
120 enum ice_status
121 ice_aq_start_lldp(struct ice_hw *hw, bool persist, struct ice_sq_cd *cd)
122 {
123         struct ice_aqc_lldp_start *cmd;
124         struct ice_aq_desc desc;
125
126         cmd = &desc.params.lldp_start;
127
128         ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_start);
129
130         cmd->command = ICE_AQ_LLDP_AGENT_START;
131
132         if (persist)
133                 cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_ENA;
134
135         return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
136 }
137
138 /**
139  * ice_aq_set_lldp_mib - Set the LLDP MIB
140  * @hw: pointer to the HW struct
141  * @mib_type: Local, Remote or both Local and Remote MIBs
142  * @buf: pointer to the caller-supplied buffer to store the MIB block
143  * @buf_size: size of the buffer (in bytes)
144  * @cd: pointer to command details structure or NULL
145  *
146  * Set the LLDP MIB. (0x0A08)
147  */
148 enum ice_status
149 ice_aq_set_lldp_mib(struct ice_hw *hw, u8 mib_type, void *buf, u16 buf_size,
150                     struct ice_sq_cd *cd)
151 {
152         struct ice_aqc_lldp_set_local_mib *cmd;
153         struct ice_aq_desc desc;
154
155         cmd = &desc.params.lldp_set_mib;
156
157         if (buf_size == 0 || !buf)
158                 return ICE_ERR_PARAM;
159
160         ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_local_mib);
161
162         desc.flags |= CPU_TO_LE16((u16)ICE_AQ_FLAG_RD);
163         desc.datalen = CPU_TO_LE16(buf_size);
164
165         cmd->type = mib_type;
166         cmd->length = CPU_TO_LE16(buf_size);
167
168         return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
169 }
170
171 /**
172  * ice_get_dcbx_status
173  * @hw: pointer to the HW struct
174  *
175  * Get the DCBX status from the Firmware
176  */
177 u8 ice_get_dcbx_status(struct ice_hw *hw)
178 {
179         u32 reg;
180
181         reg = rd32(hw, PRTDCB_GENS);
182         return (u8)((reg & PRTDCB_GENS_DCBX_STATUS_M) >>
183                     PRTDCB_GENS_DCBX_STATUS_S);
184 }
185
186 /**
187  * ice_parse_ieee_ets_common_tlv
188  * @buf: Data buffer to be parsed for ETS CFG/REC data
189  * @ets_cfg: Container to store parsed data
190  *
191  * Parses the common data of IEEE 802.1Qaz ETS CFG/REC TLV
192  */
193 static void
194 ice_parse_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
195 {
196         u8 offset = 0;
197         int i;
198
199         /* Priority Assignment Table (4 octets)
200          * Octets:|    1    |    2    |    3    |    4    |
201          *        -----------------------------------------
202          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
203          *        -----------------------------------------
204          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
205          *        -----------------------------------------
206          */
207         for (i = 0; i < 4; i++) {
208                 ets_cfg->prio_table[i * 2] =
209                         ((buf[offset] & ICE_IEEE_ETS_PRIO_1_M) >>
210                          ICE_IEEE_ETS_PRIO_1_S);
211                 ets_cfg->prio_table[i * 2 + 1] =
212                         ((buf[offset] & ICE_IEEE_ETS_PRIO_0_M) >>
213                          ICE_IEEE_ETS_PRIO_0_S);
214                 offset++;
215         }
216
217         /* TC Bandwidth Table (8 octets)
218          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
219          *        ---------------------------------
220          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
221          *        ---------------------------------
222          *
223          * TSA Assignment Table (8 octets)
224          * Octets:| 9 | 10| 11| 12| 13| 14| 15| 16|
225          *        ---------------------------------
226          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
227          *        ---------------------------------
228          */
229         ice_for_each_traffic_class(i) {
230                 ets_cfg->tcbwtable[i] = buf[offset];
231                 ets_cfg->tsatable[i] = buf[ICE_MAX_TRAFFIC_CLASS + offset++];
232         }
233 }
234
235 /**
236  * ice_parse_ieee_etscfg_tlv
237  * @tlv: IEEE 802.1Qaz ETS CFG TLV
238  * @dcbcfg: Local store to update ETS CFG data
239  *
240  * Parses IEEE 802.1Qaz ETS CFG TLV
241  */
242 static void
243 ice_parse_ieee_etscfg_tlv(struct ice_lldp_org_tlv *tlv,
244                           struct ice_dcbx_cfg *dcbcfg)
245 {
246         struct ice_dcb_ets_cfg *etscfg;
247         u8 *buf = tlv->tlvinfo;
248
249         /* First Octet post subtype
250          * --------------------------
251          * |will-|CBS  | Re-  | Max |
252          * |ing  |     |served| TCs |
253          * --------------------------
254          * |1bit | 1bit|3 bits|3bits|
255          */
256         etscfg = &dcbcfg->etscfg;
257         etscfg->willing = ((buf[0] & ICE_IEEE_ETS_WILLING_M) >>
258                            ICE_IEEE_ETS_WILLING_S);
259         etscfg->cbs = ((buf[0] & ICE_IEEE_ETS_CBS_M) >> ICE_IEEE_ETS_CBS_S);
260         etscfg->maxtcs = ((buf[0] & ICE_IEEE_ETS_MAXTC_M) >>
261                           ICE_IEEE_ETS_MAXTC_S);
262
263         /* Begin parsing at Priority Assignment Table (offset 1 in buf) */
264         ice_parse_ieee_ets_common_tlv(&buf[1], etscfg);
265 }
266
267 /**
268  * ice_parse_ieee_etsrec_tlv
269  * @tlv: IEEE 802.1Qaz ETS REC TLV
270  * @dcbcfg: Local store to update ETS REC data
271  *
272  * Parses IEEE 802.1Qaz ETS REC TLV
273  */
274 static void
275 ice_parse_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
276                           struct ice_dcbx_cfg *dcbcfg)
277 {
278         u8 *buf = tlv->tlvinfo;
279
280         /* Begin parsing at Priority Assignment Table (offset 1 in buf) */
281         ice_parse_ieee_ets_common_tlv(&buf[1], &dcbcfg->etsrec);
282 }
283
284 /**
285  * ice_parse_ieee_pfccfg_tlv
286  * @tlv: IEEE 802.1Qaz PFC CFG TLV
287  * @dcbcfg: Local store to update PFC CFG data
288  *
289  * Parses IEEE 802.1Qaz PFC CFG TLV
290  */
291 static void
292 ice_parse_ieee_pfccfg_tlv(struct ice_lldp_org_tlv *tlv,
293                           struct ice_dcbx_cfg *dcbcfg)
294 {
295         u8 *buf = tlv->tlvinfo;
296
297         /* ----------------------------------------
298          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
299          * |ing  |     |served| cap |              |
300          * -----------------------------------------
301          * |1bit | 1bit|2 bits|4bits| 1 octet      |
302          */
303         dcbcfg->pfc.willing = ((buf[0] & ICE_IEEE_PFC_WILLING_M) >>
304                                ICE_IEEE_PFC_WILLING_S);
305         dcbcfg->pfc.mbc = ((buf[0] & ICE_IEEE_PFC_MBC_M) >> ICE_IEEE_PFC_MBC_S);
306         dcbcfg->pfc.pfccap = ((buf[0] & ICE_IEEE_PFC_CAP_M) >>
307                               ICE_IEEE_PFC_CAP_S);
308         dcbcfg->pfc.pfcena = buf[1];
309 }
310
311 /**
312  * ice_parse_ieee_app_tlv
313  * @tlv: IEEE 802.1Qaz APP TLV
314  * @dcbcfg: Local store to update APP PRIO data
315  *
316  * Parses IEEE 802.1Qaz APP PRIO TLV
317  */
318 static void
319 ice_parse_ieee_app_tlv(struct ice_lldp_org_tlv *tlv,
320                        struct ice_dcbx_cfg *dcbcfg)
321 {
322         u16 offset = 0;
323         u16 typelen;
324         int i = 0;
325         u16 len;
326         u8 *buf;
327
328         typelen = NTOHS(tlv->typelen);
329         len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
330         buf = tlv->tlvinfo;
331
332         /* Removing sizeof(ouisubtype) and reserved byte from len.
333          * Remaining len div 3 is number of APP TLVs.
334          */
335         len -= (sizeof(tlv->ouisubtype) + 1);
336
337         /* Move offset to App Priority Table */
338         offset++;
339
340         /* Application Priority Table (3 octets)
341          * Octets:|         1          |    2    |    3    |
342          *        -----------------------------------------
343          *        |Priority|Rsrvd| Sel |    Protocol ID    |
344          *        -----------------------------------------
345          *   Bits:|23    21|20 19|18 16|15                0|
346          *        -----------------------------------------
347          */
348         while (offset < len) {
349                 dcbcfg->app[i].priority = ((buf[offset] &
350                                             ICE_IEEE_APP_PRIO_M) >>
351                                            ICE_IEEE_APP_PRIO_S);
352                 dcbcfg->app[i].selector = ((buf[offset] &
353                                             ICE_IEEE_APP_SEL_M) >>
354                                            ICE_IEEE_APP_SEL_S);
355                 dcbcfg->app[i].prot_id = (buf[offset + 1] << 0x8) |
356                         buf[offset + 2];
357                 /* Move to next app */
358                 offset += 3;
359                 i++;
360                 if (i >= ICE_DCBX_MAX_APPS)
361                         break;
362         }
363
364         dcbcfg->numapps = i;
365 }
366
367 /**
368  * ice_parse_ieee_tlv
369  * @tlv: IEEE 802.1Qaz TLV
370  * @dcbcfg: Local store to update ETS REC data
371  *
372  * Get the TLV subtype and send it to parsing function
373  * based on the subtype value
374  */
375 static void
376 ice_parse_ieee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
377 {
378         u32 ouisubtype;
379         u8 subtype;
380
381         ouisubtype = NTOHL(tlv->ouisubtype);
382         subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
383                        ICE_LLDP_TLV_SUBTYPE_S);
384         switch (subtype) {
385         case ICE_IEEE_SUBTYPE_ETS_CFG:
386                 ice_parse_ieee_etscfg_tlv(tlv, dcbcfg);
387                 break;
388         case ICE_IEEE_SUBTYPE_ETS_REC:
389                 ice_parse_ieee_etsrec_tlv(tlv, dcbcfg);
390                 break;
391         case ICE_IEEE_SUBTYPE_PFC_CFG:
392                 ice_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
393                 break;
394         case ICE_IEEE_SUBTYPE_APP_PRI:
395                 ice_parse_ieee_app_tlv(tlv, dcbcfg);
396                 break;
397         default:
398                 break;
399         }
400 }
401
402 /**
403  * ice_parse_cee_pgcfg_tlv
404  * @tlv: CEE DCBX PG CFG TLV
405  * @dcbcfg: Local store to update ETS CFG data
406  *
407  * Parses CEE DCBX PG CFG TLV
408  */
409 static void
410 ice_parse_cee_pgcfg_tlv(struct ice_cee_feat_tlv *tlv,
411                         struct ice_dcbx_cfg *dcbcfg)
412 {
413         struct ice_dcb_ets_cfg *etscfg;
414         u8 *buf = tlv->tlvinfo;
415         u16 offset = 0;
416         int i;
417
418         etscfg = &dcbcfg->etscfg;
419
420         if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
421                 etscfg->willing = 1;
422
423         etscfg->cbs = 0;
424         /* Priority Group Table (4 octets)
425          * Octets:|    1    |    2    |    3    |    4    |
426          *        -----------------------------------------
427          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
428          *        -----------------------------------------
429          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
430          *        -----------------------------------------
431          */
432         for (i = 0; i < 4; i++) {
433                 etscfg->prio_table[i * 2] =
434                         ((buf[offset] & ICE_CEE_PGID_PRIO_1_M) >>
435                          ICE_CEE_PGID_PRIO_1_S);
436                 etscfg->prio_table[i * 2 + 1] =
437                         ((buf[offset] & ICE_CEE_PGID_PRIO_0_M) >>
438                          ICE_CEE_PGID_PRIO_0_S);
439                 offset++;
440         }
441
442         /* PG Percentage Table (8 octets)
443          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
444          *        ---------------------------------
445          *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
446          *        ---------------------------------
447          */
448         ice_for_each_traffic_class(i)
449                 etscfg->tcbwtable[i] = buf[offset++];
450
451         /* Number of TCs supported (1 octet) */
452         etscfg->maxtcs = buf[offset];
453 }
454
455 /**
456  * ice_parse_cee_pfccfg_tlv
457  * @tlv: CEE DCBX PFC CFG TLV
458  * @dcbcfg: Local store to update PFC CFG data
459  *
460  * Parses CEE DCBX PFC CFG TLV
461  */
462 static void
463 ice_parse_cee_pfccfg_tlv(struct ice_cee_feat_tlv *tlv,
464                          struct ice_dcbx_cfg *dcbcfg)
465 {
466         u8 *buf = tlv->tlvinfo;
467
468         if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
469                 dcbcfg->pfc.willing = 1;
470
471         /* ------------------------
472          * | PFC Enable | PFC TCs |
473          * ------------------------
474          * | 1 octet    | 1 octet |
475          */
476         dcbcfg->pfc.pfcena = buf[0];
477         dcbcfg->pfc.pfccap = buf[1];
478 }
479
480 /**
481  * ice_parse_cee_app_tlv
482  * @tlv: CEE DCBX APP TLV
483  * @dcbcfg: Local store to update APP PRIO data
484  *
485  * Parses CEE DCBX APP PRIO TLV
486  */
487 static void
488 ice_parse_cee_app_tlv(struct ice_cee_feat_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
489 {
490         u16 len, typelen, offset = 0;
491         struct ice_cee_app_prio *app;
492         u8 i;
493
494         typelen = NTOHS(tlv->hdr.typelen);
495         len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
496
497         dcbcfg->numapps = len / sizeof(*app);
498         if (!dcbcfg->numapps)
499                 return;
500         if (dcbcfg->numapps > ICE_DCBX_MAX_APPS)
501                 dcbcfg->numapps = ICE_DCBX_MAX_APPS;
502
503         for (i = 0; i < dcbcfg->numapps; i++) {
504                 u8 up, selector;
505
506                 app = (struct ice_cee_app_prio *)(tlv->tlvinfo + offset);
507                 for (up = 0; up < ICE_MAX_USER_PRIORITY; up++)
508                         if (app->prio_map & BIT(up))
509                                 break;
510
511                 dcbcfg->app[i].priority = up;
512
513                 /* Get Selector from lower 2 bits, and convert to IEEE */
514                 selector = (app->upper_oui_sel & ICE_CEE_APP_SELECTOR_M);
515                 switch (selector) {
516                 case ICE_CEE_APP_SEL_ETHTYPE:
517                         dcbcfg->app[i].selector = ICE_APP_SEL_ETHTYPE;
518                         break;
519                 case ICE_CEE_APP_SEL_TCPIP:
520                         dcbcfg->app[i].selector = ICE_APP_SEL_TCPIP;
521                         break;
522                 default:
523                         /* Keep selector as it is for unknown types */
524                         dcbcfg->app[i].selector = selector;
525                 }
526
527                 dcbcfg->app[i].prot_id = NTOHS(app->protocol);
528                 /* Move to next app */
529                 offset += sizeof(*app);
530         }
531 }
532
533 /**
534  * ice_parse_cee_tlv
535  * @tlv: CEE DCBX TLV
536  * @dcbcfg: Local store to update DCBX config data
537  *
538  * Get the TLV subtype and send it to parsing function
539  * based on the subtype value
540  */
541 static void
542 ice_parse_cee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
543 {
544         struct ice_cee_feat_tlv *sub_tlv;
545         u8 subtype, feat_tlv_count = 0;
546         u16 len, tlvlen, typelen;
547         u32 ouisubtype;
548
549         ouisubtype = NTOHL(tlv->ouisubtype);
550         subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
551                        ICE_LLDP_TLV_SUBTYPE_S);
552         /* Return if not CEE DCBX */
553         if (subtype != ICE_CEE_DCBX_TYPE)
554                 return;
555
556         typelen = NTOHS(tlv->typelen);
557         tlvlen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
558         len = sizeof(tlv->typelen) + sizeof(ouisubtype) +
559                 sizeof(struct ice_cee_ctrl_tlv);
560         /* Return if no CEE DCBX Feature TLVs */
561         if (tlvlen <= len)
562                 return;
563
564         sub_tlv = (struct ice_cee_feat_tlv *)((char *)tlv + len);
565         while (feat_tlv_count < ICE_CEE_MAX_FEAT_TYPE) {
566                 u16 sublen;
567
568                 typelen = NTOHS(sub_tlv->hdr.typelen);
569                 sublen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
570                 subtype = (u8)((typelen & ICE_LLDP_TLV_TYPE_M) >>
571                                ICE_LLDP_TLV_TYPE_S);
572                 switch (subtype) {
573                 case ICE_CEE_SUBTYPE_PG_CFG:
574                         ice_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
575                         break;
576                 case ICE_CEE_SUBTYPE_PFC_CFG:
577                         ice_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
578                         break;
579                 case ICE_CEE_SUBTYPE_APP_PRI:
580                         ice_parse_cee_app_tlv(sub_tlv, dcbcfg);
581                         break;
582                 default:
583                         return; /* Invalid Sub-type return */
584                 }
585                 feat_tlv_count++;
586                 /* Move to next sub TLV */
587                 sub_tlv = (struct ice_cee_feat_tlv *)
588                           ((char *)sub_tlv + sizeof(sub_tlv->hdr.typelen) +
589                            sublen);
590         }
591 }
592
593 /**
594  * ice_parse_org_tlv
595  * @tlv: Organization specific TLV
596  * @dcbcfg: Local store to update ETS REC data
597  *
598  * Currently only IEEE 802.1Qaz TLV is supported, all others
599  * will be returned
600  */
601 static void
602 ice_parse_org_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
603 {
604         u32 ouisubtype;
605         u32 oui;
606
607         ouisubtype = NTOHL(tlv->ouisubtype);
608         oui = ((ouisubtype & ICE_LLDP_TLV_OUI_M) >> ICE_LLDP_TLV_OUI_S);
609         switch (oui) {
610         case ICE_IEEE_8021QAZ_OUI:
611                 ice_parse_ieee_tlv(tlv, dcbcfg);
612                 break;
613         case ICE_CEE_DCBX_OUI:
614                 ice_parse_cee_tlv(tlv, dcbcfg);
615                 break;
616         default:
617                 break;
618         }
619 }
620
621 /**
622  * ice_lldp_to_dcb_cfg
623  * @lldpmib: LLDPDU to be parsed
624  * @dcbcfg: store for LLDPDU data
625  *
626  * Parse DCB configuration from the LLDPDU
627  */
628 enum ice_status
629 ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
630 {
631         struct ice_lldp_org_tlv *tlv;
632         enum ice_status ret = ICE_SUCCESS;
633         u16 offset = 0;
634         u16 typelen;
635         u16 type;
636         u16 len;
637
638         if (!lldpmib || !dcbcfg)
639                 return ICE_ERR_PARAM;
640
641         /* set to the start of LLDPDU */
642         lldpmib += ETH_HEADER_LEN;
643         tlv = (struct ice_lldp_org_tlv *)lldpmib;
644         while (1) {
645                 typelen = NTOHS(tlv->typelen);
646                 type = ((typelen & ICE_LLDP_TLV_TYPE_M) >> ICE_LLDP_TLV_TYPE_S);
647                 len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
648                 offset += sizeof(typelen) + len;
649
650                 /* END TLV or beyond LLDPDU size */
651                 if (type == ICE_TLV_TYPE_END || offset > ICE_LLDPDU_SIZE)
652                         break;
653
654                 switch (type) {
655                 case ICE_TLV_TYPE_ORG:
656                         ice_parse_org_tlv(tlv, dcbcfg);
657                         break;
658                 default:
659                         break;
660                 }
661
662                 /* Move to next TLV */
663                 tlv = (struct ice_lldp_org_tlv *)
664                       ((char *)tlv + sizeof(tlv->typelen) + len);
665         }
666
667         return ret;
668 }
669
670 /**
671  * ice_aq_get_dcb_cfg
672  * @hw: pointer to the HW struct
673  * @mib_type: MIB type for the query
674  * @bridgetype: bridge type for the query (remote)
675  * @dcbcfg: store for LLDPDU data
676  *
677  * Query DCB configuration from the firmware
678  */
679 enum ice_status
680 ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,
681                    struct ice_dcbx_cfg *dcbcfg)
682 {
683         enum ice_status ret;
684         u8 *lldpmib;
685
686         /* Allocate the LLDPDU */
687         lldpmib = (u8 *)ice_malloc(hw, ICE_LLDPDU_SIZE);
688         if (!lldpmib)
689                 return ICE_ERR_NO_MEMORY;
690
691         ret = ice_aq_get_lldp_mib(hw, bridgetype, mib_type, (void *)lldpmib,
692                                   ICE_LLDPDU_SIZE, NULL, NULL, NULL);
693
694         if (ret == ICE_SUCCESS)
695                 /* Parse LLDP MIB to get DCB configuration */
696                 ret = ice_lldp_to_dcb_cfg(lldpmib, dcbcfg);
697
698         ice_free(hw, lldpmib);
699
700         return ret;
701 }
702
703 /**
704  * ice_aq_start_stop_dcbx - Start/Stop DCBX service in FW
705  * @hw: pointer to the HW struct
706  * @start_dcbx_agent: True if DCBX Agent needs to be started
707  *                    False if DCBX Agent needs to be stopped
708  * @dcbx_agent_status: FW indicates back the DCBX agent status
709  *                     True if DCBX Agent is active
710  *                     False if DCBX Agent is stopped
711  * @cd: pointer to command details structure or NULL
712  *
713  * Start/Stop the embedded dcbx Agent. In case that this wrapper function
714  * returns ICE_SUCCESS, caller will need to check if FW returns back the same
715  * value as stated in dcbx_agent_status, and react accordingly. (0x0A09)
716  */
717 enum ice_status
718 ice_aq_start_stop_dcbx(struct ice_hw *hw, bool start_dcbx_agent,
719                        bool *dcbx_agent_status, struct ice_sq_cd *cd)
720 {
721         struct ice_aqc_lldp_stop_start_specific_agent *cmd;
722         enum ice_status status;
723         struct ice_aq_desc desc;
724         u16 opcode;
725
726         cmd = &desc.params.lldp_agent_ctrl;
727
728         opcode = ice_aqc_opc_lldp_stop_start_specific_agent;
729
730         ice_fill_dflt_direct_cmd_desc(&desc, opcode);
731
732         if (start_dcbx_agent)
733                 cmd->command = ICE_AQC_START_STOP_AGENT_START_DCBX;
734
735         status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
736
737         *dcbx_agent_status = false;
738
739         if (status == ICE_SUCCESS &&
740             cmd->command == ICE_AQC_START_STOP_AGENT_START_DCBX)
741                 *dcbx_agent_status = true;
742
743         return status;
744 }
745
746 /**
747  * ice_aq_get_cee_dcb_cfg
748  * @hw: pointer to the HW struct
749  * @buff: response buffer that stores CEE operational configuration
750  * @cd: pointer to command details structure or NULL
751  *
752  * Get CEE DCBX mode operational configuration from firmware (0x0A07)
753  */
754 enum ice_status
755 ice_aq_get_cee_dcb_cfg(struct ice_hw *hw,
756                        struct ice_aqc_get_cee_dcb_cfg_resp *buff,
757                        struct ice_sq_cd *cd)
758 {
759         struct ice_aq_desc desc;
760
761         ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cee_dcb_cfg);
762
763         return ice_aq_send_cmd(hw, &desc, (void *)buff, sizeof(*buff), cd);
764 }
765
766 /**
767  * ice_cee_to_dcb_cfg
768  * @cee_cfg: pointer to CEE configuration struct
769  * @dcbcfg: DCB configuration struct
770  *
771  * Convert CEE configuration from firmware to DCB configuration
772  */
773 static void
774 ice_cee_to_dcb_cfg(struct ice_aqc_get_cee_dcb_cfg_resp *cee_cfg,
775                    struct ice_dcbx_cfg *dcbcfg)
776 {
777         u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
778         u32 ice_aqc_cee_status_mask, ice_aqc_cee_status_shift;
779         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
780         u8 i, err, sync, oper, app_index, ice_app_sel_type;
781         u16 ice_aqc_cee_app_mask, ice_aqc_cee_app_shift;
782         u16 ice_app_prot_id_type;
783
784         /* CEE PG data to ETS config */
785         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
786
787         /* Note that the FW creates the oper_prio_tc nibbles reversed
788          * from those in the CEE Priority Group sub-TLV.
789          */
790         for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
791                 dcbcfg->etscfg.prio_table[i * 2] =
792                         ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_0_M) >>
793                          ICE_CEE_PGID_PRIO_0_S);
794                 dcbcfg->etscfg.prio_table[i * 2 + 1] =
795                         ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_1_M) >>
796                          ICE_CEE_PGID_PRIO_1_S);
797         }
798
799         ice_for_each_traffic_class(i) {
800                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
801
802                 if (dcbcfg->etscfg.prio_table[i] == ICE_CEE_PGID_STRICT) {
803                         /* Map it to next empty TC */
804                         dcbcfg->etscfg.prio_table[i] = cee_cfg->oper_num_tc - 1;
805                         dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;
806                 } else {
807                         dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;
808                 }
809         }
810
811         /* CEE PFC data to ETS config */
812         dcbcfg->pfc.pfcena = cee_cfg->oper_pfc_en;
813         dcbcfg->pfc.pfccap = ICE_MAX_TRAFFIC_CLASS;
814
815         app_index = 0;
816         for (i = 0; i < 3; i++) {
817                 if (i == 0) {
818                         /* FCoE APP */
819                         ice_aqc_cee_status_mask = ICE_AQC_CEE_FCOE_STATUS_M;
820                         ice_aqc_cee_status_shift = ICE_AQC_CEE_FCOE_STATUS_S;
821                         ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FCOE_M;
822                         ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FCOE_S;
823                         ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
824                         ice_app_prot_id_type = ICE_APP_PROT_ID_FCOE;
825                 } else if (i == 1) {
826                         /* iSCSI APP */
827                         ice_aqc_cee_status_mask = ICE_AQC_CEE_ISCSI_STATUS_M;
828                         ice_aqc_cee_status_shift = ICE_AQC_CEE_ISCSI_STATUS_S;
829                         ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_ISCSI_M;
830                         ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_ISCSI_S;
831                         ice_app_sel_type = ICE_APP_SEL_TCPIP;
832                         ice_app_prot_id_type = ICE_APP_PROT_ID_ISCSI;
833                 } else {
834                         /* FIP APP */
835                         ice_aqc_cee_status_mask = ICE_AQC_CEE_FIP_STATUS_M;
836                         ice_aqc_cee_status_shift = ICE_AQC_CEE_FIP_STATUS_S;
837                         ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FIP_M;
838                         ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FIP_S;
839                         ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
840                         ice_app_prot_id_type = ICE_APP_PROT_ID_FIP;
841                 }
842
843                 status = (tlv_status & ice_aqc_cee_status_mask) >>
844                          ice_aqc_cee_status_shift;
845                 err = (status & ICE_TLV_STATUS_ERR) ? 1 : 0;
846                 sync = (status & ICE_TLV_STATUS_SYNC) ? 1 : 0;
847                 oper = (status & ICE_TLV_STATUS_OPER) ? 1 : 0;
848                 /* Add FCoE/iSCSI/FIP APP if Error is False and
849                  * Oper/Sync is True
850                  */
851                 if (!err && sync && oper) {
852                         dcbcfg->app[app_index].priority =
853                                 (app_prio & ice_aqc_cee_app_mask) >>
854                                 ice_aqc_cee_app_shift;
855                         dcbcfg->app[app_index].selector = ice_app_sel_type;
856                         dcbcfg->app[app_index].prot_id = ice_app_prot_id_type;
857                         app_index++;
858                 }
859         }
860
861         dcbcfg->numapps = app_index;
862 }
863
864 /**
865  * ice_get_ieee_dcb_cfg
866  * @pi: port information structure
867  * @dcbx_mode: mode of DCBX (IEEE or CEE)
868  *
869  * Get IEEE or CEE mode DCB configuration from the Firmware
870  */
871 STATIC enum ice_status
872 ice_get_ieee_or_cee_dcb_cfg(struct ice_port_info *pi, u8 dcbx_mode)
873 {
874         struct ice_dcbx_cfg *dcbx_cfg = NULL;
875         enum ice_status ret;
876
877         if (!pi)
878                 return ICE_ERR_PARAM;
879
880         if (dcbx_mode == ICE_DCBX_MODE_IEEE)
881                 dcbx_cfg = &pi->local_dcbx_cfg;
882         else if (dcbx_mode == ICE_DCBX_MODE_CEE)
883                 dcbx_cfg = &pi->desired_dcbx_cfg;
884
885         /* Get Local DCB Config in case of ICE_DCBX_MODE_IEEE
886          * or get CEE DCB Desired Config in case of ICE_DCBX_MODE_CEE
887          */
888         ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_LOCAL,
889                                  ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
890         if (ret)
891                 goto out;
892
893         /* Get Remote DCB Config */
894         dcbx_cfg = &pi->remote_dcbx_cfg;
895         ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE,
896                                  ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
897         /* Don't treat ENOENT as an error for Remote MIBs */
898         if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
899                 ret = ICE_SUCCESS;
900
901 out:
902         return ret;
903 }
904
905 /**
906  * ice_get_dcb_cfg
907  * @pi: port information structure
908  *
909  * Get DCB configuration from the Firmware
910  */
911 enum ice_status ice_get_dcb_cfg(struct ice_port_info *pi)
912 {
913         struct ice_aqc_get_cee_dcb_cfg_resp cee_cfg;
914         struct ice_dcbx_cfg *dcbx_cfg;
915         enum ice_status ret;
916
917         if (!pi)
918                 return ICE_ERR_PARAM;
919
920         ret = ice_aq_get_cee_dcb_cfg(pi->hw, &cee_cfg, NULL);
921         if (ret == ICE_SUCCESS) {
922                 /* CEE mode */
923                 dcbx_cfg = &pi->local_dcbx_cfg;
924                 dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_CEE;
925                 dcbx_cfg->tlv_status = LE32_TO_CPU(cee_cfg.tlv_status);
926                 ice_cee_to_dcb_cfg(&cee_cfg, dcbx_cfg);
927                 ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_CEE);
928         } else if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) {
929                 /* CEE mode not enabled try querying IEEE data */
930                 dcbx_cfg = &pi->local_dcbx_cfg;
931                 dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE;
932                 ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_IEEE);
933         }
934
935         return ret;
936 }
937
938 /**
939  * ice_init_dcb
940  * @hw: pointer to the HW struct
941  * @enable_mib_change: enable MIB change event
942  *
943  * Update DCB configuration from the Firmware
944  */
945 enum ice_status ice_init_dcb(struct ice_hw *hw, bool enable_mib_change)
946 {
947         struct ice_port_info *pi = hw->port_info;
948         enum ice_status ret = ICE_SUCCESS;
949
950         if (!hw->func_caps.common_cap.dcb)
951                 return ICE_ERR_NOT_SUPPORTED;
952
953         pi->is_sw_lldp = true;
954
955         /* Get DCBX status */
956         pi->dcbx_status = ice_get_dcbx_status(hw);
957
958         if (pi->dcbx_status == ICE_DCBX_STATUS_DONE ||
959             pi->dcbx_status == ICE_DCBX_STATUS_IN_PROGRESS ||
960             pi->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {
961                 /* Get current DCBX configuration */
962                 ret = ice_get_dcb_cfg(pi);
963                 pi->is_sw_lldp = (hw->adminq.sq_last_status == ICE_AQ_RC_EPERM);
964                 if (ret)
965                         return ret;
966         } else if (pi->dcbx_status == ICE_DCBX_STATUS_DIS) {
967                 return ICE_ERR_NOT_READY;
968         }
969
970         /* Configure the LLDP MIB change event */
971         if (enable_mib_change) {
972                 ret = ice_aq_cfg_lldp_mib_change(hw, true, NULL);
973                 if (!ret)
974                         pi->is_sw_lldp = false;
975         }
976
977         return ret;
978 }
979
980 /**
981  * ice_cfg_lldp_mib_change
982  * @hw: pointer to the HW struct
983  * @ena_mib: enable/disable MIB change event
984  *
985  * Configure (disable/enable) MIB
986  */
987 enum ice_status ice_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_mib)
988 {
989         struct ice_port_info *pi = hw->port_info;
990         enum ice_status ret;
991
992         if (!hw->func_caps.common_cap.dcb)
993                 return ICE_ERR_NOT_SUPPORTED;
994
995         /* Get DCBX status */
996         pi->dcbx_status = ice_get_dcbx_status(hw);
997
998         if (pi->dcbx_status == ICE_DCBX_STATUS_DIS)
999                 return ICE_ERR_NOT_READY;
1000
1001         ret = ice_aq_cfg_lldp_mib_change(hw, ena_mib, NULL);
1002         if (!ret)
1003                 pi->is_sw_lldp = !ena_mib;
1004
1005         return ret;
1006 }
1007
1008 /**
1009  * ice_add_ieee_ets_common_tlv
1010  * @buf: Data buffer to be populated with ice_dcb_ets_cfg data
1011  * @ets_cfg: Container for ice_dcb_ets_cfg data
1012  *
1013  * Populate the TLV buffer with ice_dcb_ets_cfg data
1014  */
1015 static void
1016 ice_add_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
1017 {
1018         u8 priority0, priority1;
1019         u8 offset = 0;
1020         int i;
1021
1022         /* Priority Assignment Table (4 octets)
1023          * Octets:|    1    |    2    |    3    |    4    |
1024          *        -----------------------------------------
1025          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1026          *        -----------------------------------------
1027          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1028          *        -----------------------------------------
1029          */
1030         for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
1031                 priority0 = ets_cfg->prio_table[i * 2] & 0xF;
1032                 priority1 = ets_cfg->prio_table[i * 2 + 1] & 0xF;
1033                 buf[offset] = (priority0 << ICE_IEEE_ETS_PRIO_1_S) | priority1;
1034                 offset++;
1035         }
1036
1037         /* TC Bandwidth Table (8 octets)
1038          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1039          *        ---------------------------------
1040          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1041          *        ---------------------------------
1042          *
1043          * TSA Assignment Table (8 octets)
1044          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1045          *        ---------------------------------
1046          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1047          *        ---------------------------------
1048          */
1049         ice_for_each_traffic_class(i) {
1050                 buf[offset] = ets_cfg->tcbwtable[i];
1051                 buf[ICE_MAX_TRAFFIC_CLASS + offset] = ets_cfg->tsatable[i];
1052                 offset++;
1053         }
1054 }
1055
1056 /**
1057  * ice_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
1058  * @tlv: Fill the ETS config data in IEEE format
1059  * @dcbcfg: Local store which holds the DCB Config
1060  *
1061  * Prepare IEEE 802.1Qaz ETS CFG TLV
1062  */
1063 static void
1064 ice_add_ieee_ets_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1065 {
1066         struct ice_dcb_ets_cfg *etscfg;
1067         u8 *buf = tlv->tlvinfo;
1068         u8 maxtcwilling = 0;
1069         u32 ouisubtype;
1070         u16 typelen;
1071
1072         typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1073                    ICE_IEEE_ETS_TLV_LEN);
1074         tlv->typelen = HTONS(typelen);
1075
1076         ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1077                       ICE_IEEE_SUBTYPE_ETS_CFG);
1078         tlv->ouisubtype = HTONL(ouisubtype);
1079
1080         /* First Octet post subtype
1081          * --------------------------
1082          * |will-|CBS  | Re-  | Max |
1083          * |ing  |     |served| TCs |
1084          * --------------------------
1085          * |1bit | 1bit|3 bits|3bits|
1086          */
1087         etscfg = &dcbcfg->etscfg;
1088         if (etscfg->willing)
1089                 maxtcwilling = BIT(ICE_IEEE_ETS_WILLING_S);
1090         maxtcwilling |= etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;
1091         buf[0] = maxtcwilling;
1092
1093         /* Begin adding at Priority Assignment Table (offset 1 in buf) */
1094         ice_add_ieee_ets_common_tlv(&buf[1], etscfg);
1095 }
1096
1097 /**
1098  * ice_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1099  * @tlv: Fill ETS Recommended TLV in IEEE format
1100  * @dcbcfg: Local store which holds the DCB Config
1101  *
1102  * Prepare IEEE 802.1Qaz ETS REC TLV
1103  */
1104 static void
1105 ice_add_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
1106                         struct ice_dcbx_cfg *dcbcfg)
1107 {
1108         struct ice_dcb_ets_cfg *etsrec;
1109         u8 *buf = tlv->tlvinfo;
1110         u32 ouisubtype;
1111         u16 typelen;
1112
1113         typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1114                    ICE_IEEE_ETS_TLV_LEN);
1115         tlv->typelen = HTONS(typelen);
1116
1117         ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1118                       ICE_IEEE_SUBTYPE_ETS_REC);
1119         tlv->ouisubtype = HTONL(ouisubtype);
1120
1121         etsrec = &dcbcfg->etsrec;
1122
1123         /* First Octet is reserved */
1124         /* Begin adding at Priority Assignment Table (offset 1 in buf) */
1125         ice_add_ieee_ets_common_tlv(&buf[1], etsrec);
1126 }
1127
1128 /**
1129  * ice_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1130  * @tlv: Fill PFC TLV in IEEE format
1131  * @dcbcfg: Local store which holds the PFC CFG data
1132  *
1133  * Prepare IEEE 802.1Qaz PFC CFG TLV
1134  */
1135 static void
1136 ice_add_ieee_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1137 {
1138         u8 *buf = tlv->tlvinfo;
1139         u32 ouisubtype;
1140         u16 typelen;
1141
1142         typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1143                    ICE_IEEE_PFC_TLV_LEN);
1144         tlv->typelen = HTONS(typelen);
1145
1146         ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1147                       ICE_IEEE_SUBTYPE_PFC_CFG);
1148         tlv->ouisubtype = HTONL(ouisubtype);
1149
1150         /* ----------------------------------------
1151          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1152          * |ing  |     |served| cap |              |
1153          * -----------------------------------------
1154          * |1bit | 1bit|2 bits|4bits| 1 octet      |
1155          */
1156         if (dcbcfg->pfc.willing)
1157                 buf[0] = BIT(ICE_IEEE_PFC_WILLING_S);
1158
1159         if (dcbcfg->pfc.mbc)
1160                 buf[0] |= BIT(ICE_IEEE_PFC_MBC_S);
1161
1162         buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1163         buf[1] = dcbcfg->pfc.pfcena;
1164 }
1165
1166 /**
1167  * ice_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1168  * @tlv: Fill APP TLV in IEEE format
1169  * @dcbcfg: Local store which holds the APP CFG data
1170  *
1171  * Prepare IEEE 802.1Qaz APP CFG TLV
1172  */
1173 static void
1174 ice_add_ieee_app_pri_tlv(struct ice_lldp_org_tlv *tlv,
1175                          struct ice_dcbx_cfg *dcbcfg)
1176 {
1177         u16 typelen, len, offset = 0;
1178         u8 priority, selector, i = 0;
1179         u8 *buf = tlv->tlvinfo;
1180         u32 ouisubtype;
1181
1182         /* No APP TLVs then just return */
1183         if (dcbcfg->numapps == 0)
1184                 return;
1185         ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1186                       ICE_IEEE_SUBTYPE_APP_PRI);
1187         tlv->ouisubtype = HTONL(ouisubtype);
1188
1189         /* Move offset to App Priority Table */
1190         offset++;
1191         /* Application Priority Table (3 octets)
1192          * Octets:|         1          |    2    |    3    |
1193          *        -----------------------------------------
1194          *        |Priority|Rsrvd| Sel |    Protocol ID    |
1195          *        -----------------------------------------
1196          *   Bits:|23    21|20 19|18 16|15                0|
1197          *        -----------------------------------------
1198          */
1199         while (i < dcbcfg->numapps) {
1200                 priority = dcbcfg->app[i].priority & 0x7;
1201                 selector = dcbcfg->app[i].selector & 0x7;
1202                 buf[offset] = (priority << ICE_IEEE_APP_PRIO_S) | selector;
1203                 buf[offset + 1] = (dcbcfg->app[i].prot_id >> 0x8) & 0xFF;
1204                 buf[offset + 2] = dcbcfg->app[i].prot_id & 0xFF;
1205                 /* Move to next app */
1206                 offset += 3;
1207                 i++;
1208                 if (i >= ICE_DCBX_MAX_APPS)
1209                         break;
1210         }
1211         /* len includes size of ouisubtype + 1 reserved + 3*numapps */
1212         len = sizeof(tlv->ouisubtype) + 1 + (i * 3);
1213         typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) | (len & 0x1FF));
1214         tlv->typelen = HTONS(typelen);
1215 }
1216
1217 /**
1218  * ice_add_dcb_tlv - Add all IEEE TLVs
1219  * @tlv: Fill TLV data in IEEE format
1220  * @dcbcfg: Local store which holds the DCB Config
1221  * @tlvid: Type of IEEE TLV
1222  *
1223  * Add tlv information
1224  */
1225 static void
1226 ice_add_dcb_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg,
1227                 u16 tlvid)
1228 {
1229         switch (tlvid) {
1230         case ICE_IEEE_TLV_ID_ETS_CFG:
1231                 ice_add_ieee_ets_tlv(tlv, dcbcfg);
1232                 break;
1233         case ICE_IEEE_TLV_ID_ETS_REC:
1234                 ice_add_ieee_etsrec_tlv(tlv, dcbcfg);
1235                 break;
1236         case ICE_IEEE_TLV_ID_PFC_CFG:
1237                 ice_add_ieee_pfc_tlv(tlv, dcbcfg);
1238                 break;
1239         case ICE_IEEE_TLV_ID_APP_PRI:
1240                 ice_add_ieee_app_pri_tlv(tlv, dcbcfg);
1241                 break;
1242         default:
1243                 break;
1244         }
1245 }
1246
1247 /**
1248  * ice_dcb_cfg_to_lldp - Convert DCB configuration to MIB format
1249  * @lldpmib: pointer to the HW struct
1250  * @miblen: length of LLDP MIB
1251  * @dcbcfg: Local store which holds the DCB Config
1252  *
1253  * Convert the DCB configuration to MIB format
1254  */
1255 void ice_dcb_cfg_to_lldp(u8 *lldpmib, u16 *miblen, struct ice_dcbx_cfg *dcbcfg)
1256 {
1257         u16 len, offset = 0, tlvid = ICE_TLV_ID_START;
1258         struct ice_lldp_org_tlv *tlv;
1259         u16 typelen;
1260
1261         tlv = (struct ice_lldp_org_tlv *)lldpmib;
1262         while (1) {
1263                 ice_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1264                 typelen = NTOHS(tlv->typelen);
1265                 len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
1266                 if (len)
1267                         offset += len + 2;
1268                 /* END TLV or beyond LLDPDU size */
1269                 if (tlvid >= ICE_TLV_ID_END_OF_LLDPPDU ||
1270                     offset > ICE_LLDPDU_SIZE)
1271                         break;
1272                 /* Move to next TLV */
1273                 if (len)
1274                         tlv = (struct ice_lldp_org_tlv *)
1275                                 ((char *)tlv + sizeof(tlv->typelen) + len);
1276         }
1277         *miblen = offset;
1278 }
1279
1280 /**
1281  * ice_set_dcb_cfg - Set the local LLDP MIB to FW
1282  * @pi: port information structure
1283  *
1284  * Set DCB configuration to the Firmware
1285  */
1286 enum ice_status ice_set_dcb_cfg(struct ice_port_info *pi)
1287 {
1288         u8 mib_type, *lldpmib = NULL;
1289         struct ice_dcbx_cfg *dcbcfg;
1290         enum ice_status ret;
1291         struct ice_hw *hw;
1292         u16 miblen;
1293
1294         if (!pi)
1295                 return ICE_ERR_PARAM;
1296
1297         hw = pi->hw;
1298
1299         /* update the HW local config */
1300         dcbcfg = &pi->local_dcbx_cfg;
1301         /* Allocate the LLDPDU */
1302         lldpmib = (u8 *)ice_malloc(hw, ICE_LLDPDU_SIZE);
1303         if (!lldpmib)
1304                 return ICE_ERR_NO_MEMORY;
1305
1306         mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB;
1307         if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)
1308                 mib_type |= SET_LOCAL_MIB_TYPE_CEE_NON_WILLING;
1309
1310         ice_dcb_cfg_to_lldp(lldpmib, &miblen, dcbcfg);
1311         ret = ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen,
1312                                   NULL);
1313
1314         ice_free(hw, lldpmib);
1315
1316         return ret;
1317 }
1318
1319 /**
1320  * ice_aq_query_port_ets - query port ets configuration
1321  * @pi: port information structure
1322  * @buf: pointer to buffer
1323  * @buf_size: buffer size in bytes
1324  * @cd: pointer to command details structure or NULL
1325  *
1326  * query current port ets configuration
1327  */
1328 enum ice_status
1329 ice_aq_query_port_ets(struct ice_port_info *pi,
1330                       struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1331                       struct ice_sq_cd *cd)
1332 {
1333         struct ice_aqc_query_port_ets *cmd;
1334         struct ice_aq_desc desc;
1335         enum ice_status status;
1336
1337         if (!pi)
1338                 return ICE_ERR_PARAM;
1339         cmd = &desc.params.port_ets;
1340         ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_port_ets);
1341         cmd->port_teid = pi->root->info.node_teid;
1342
1343         status = ice_aq_send_cmd(pi->hw, &desc, buf, buf_size, cd);
1344         return status;
1345 }
1346
1347 /**
1348  * ice_update_port_tc_tree_cfg - update TC tree configuration
1349  * @pi: port information structure
1350  * @buf: pointer to buffer
1351  *
1352  * update the SW DB with the new TC changes
1353  */
1354 enum ice_status
1355 ice_update_port_tc_tree_cfg(struct ice_port_info *pi,
1356                             struct ice_aqc_port_ets_elem *buf)
1357 {
1358         struct ice_sched_node *node, *tc_node;
1359         struct ice_aqc_get_elem elem;
1360         enum ice_status status = ICE_SUCCESS;
1361         u32 teid1, teid2;
1362         u8 i, j;
1363
1364         if (!pi)
1365                 return ICE_ERR_PARAM;
1366         /* suspend the missing TC nodes */
1367         for (i = 0; i < pi->root->num_children; i++) {
1368                 teid1 = LE32_TO_CPU(pi->root->children[i]->info.node_teid);
1369                 ice_for_each_traffic_class(j) {
1370                         teid2 = LE32_TO_CPU(buf->tc_node_teid[j]);
1371                         if (teid1 == teid2)
1372                                 break;
1373                 }
1374                 if (j < ICE_MAX_TRAFFIC_CLASS)
1375                         continue;
1376                 /* TC is missing */
1377                 pi->root->children[i]->in_use = false;
1378         }
1379         /* add the new TC nodes */
1380         ice_for_each_traffic_class(j) {
1381                 teid2 = LE32_TO_CPU(buf->tc_node_teid[j]);
1382                 if (teid2 == ICE_INVAL_TEID)
1383                         continue;
1384                 /* Is it already present in the tree ? */
1385                 for (i = 0; i < pi->root->num_children; i++) {
1386                         tc_node = pi->root->children[i];
1387                         if (!tc_node)
1388                                 continue;
1389                         teid1 = LE32_TO_CPU(tc_node->info.node_teid);
1390                         if (teid1 == teid2) {
1391                                 tc_node->tc_num = j;
1392                                 tc_node->in_use = true;
1393                                 break;
1394                         }
1395                 }
1396                 if (i < pi->root->num_children)
1397                         continue;
1398                 /* new TC */
1399                 status = ice_sched_query_elem(pi->hw, teid2, &elem);
1400                 if (!status)
1401                         status = ice_sched_add_node(pi, 1, &elem.generic[0]);
1402                 if (status)
1403                         break;
1404                 /* update the TC number */
1405                 node = ice_sched_find_node_by_teid(pi->root, teid2);
1406                 if (node)
1407                         node->tc_num = j;
1408         }
1409         return status;
1410 }
1411
1412 /**
1413  * ice_query_port_ets - query port ets configuration
1414  * @pi: port information structure
1415  * @buf: pointer to buffer
1416  * @buf_size: buffer size in bytes
1417  * @cd: pointer to command details structure or NULL
1418  *
1419  * query current port ets configuration and update the
1420  * SW DB with the TC changes
1421  */
1422 enum ice_status
1423 ice_query_port_ets(struct ice_port_info *pi,
1424                    struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1425                    struct ice_sq_cd *cd)
1426 {
1427         enum ice_status status;
1428
1429         ice_acquire_lock(&pi->sched_lock);
1430         status = ice_aq_query_port_ets(pi, buf, buf_size, cd);
1431         if (!status)
1432                 status = ice_update_port_tc_tree_cfg(pi, buf);
1433         ice_release_lock(&pi->sched_lock);
1434         return status;
1435 }