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