1282 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013-2014 Chelsio Communications. All rights reserved.4 *5 * Written by Anish Bhatt (anish@chelsio.com)6 * Casey Leedom (leedom@chelsio.com)7 */8 9#include "cxgb4.h"10 11/* DCBx version control12 */13const char * const dcb_ver_array[] = {14 "Unknown",15 "DCBx-CIN",16 "DCBx-CEE 1.01",17 "DCBx-IEEE",18 "", "", "",19 "Auto Negotiated"20};21 22static inline bool cxgb4_dcb_state_synced(enum cxgb4_dcb_state state)23{24 if (state == CXGB4_DCB_STATE_FW_ALLSYNCED ||25 state == CXGB4_DCB_STATE_HOST)26 return true;27 else28 return false;29}30 31/* Initialize a port's Data Center Bridging state.32 */33void cxgb4_dcb_state_init(struct net_device *dev)34{35 struct port_info *pi = netdev2pinfo(dev);36 struct port_dcb_info *dcb = &pi->dcb;37 int version_temp = dcb->dcb_version;38 39 memset(dcb, 0, sizeof(struct port_dcb_info));40 dcb->state = CXGB4_DCB_STATE_START;41 if (version_temp)42 dcb->dcb_version = version_temp;43 44 netdev_dbg(dev, "%s: Initializing DCB state for port[%d]\n",45 __func__, pi->port_id);46}47 48void cxgb4_dcb_version_init(struct net_device *dev)49{50 struct port_info *pi = netdev2pinfo(dev);51 struct port_dcb_info *dcb = &pi->dcb;52 53 /* Any writes here are only done on kernels that exlicitly need54 * a specific version, say < 2.6.38 which only support CEE55 */56 dcb->dcb_version = FW_PORT_DCB_VER_AUTO;57}58 59static void cxgb4_dcb_cleanup_apps(struct net_device *dev)60{61 struct port_info *pi = netdev2pinfo(dev);62 struct adapter *adap = pi->adapter;63 struct port_dcb_info *dcb = &pi->dcb;64 struct dcb_app app;65 int i, err;66 67 /* zero priority implies remove */68 app.priority = 0;69 70 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {71 /* Check if app list is exhausted */72 if (!dcb->app_priority[i].protocolid)73 break;74 75 app.protocol = dcb->app_priority[i].protocolid;76 77 if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE) {78 app.priority = dcb->app_priority[i].user_prio_map;79 app.selector = dcb->app_priority[i].sel_field + 1;80 err = dcb_ieee_delapp(dev, &app);81 } else {82 app.selector = !!(dcb->app_priority[i].sel_field);83 err = dcb_setapp(dev, &app);84 }85 86 if (err) {87 dev_err(adap->pdev_dev,88 "Failed DCB Clear %s Application Priority: sel=%d, prot=%d, err=%d\n",89 dcb_ver_array[dcb->dcb_version], app.selector,90 app.protocol, -err);91 break;92 }93 }94}95 96/* Reset a port's Data Center Bridging state. Typically used after a97 * Link Down event.98 */99void cxgb4_dcb_reset(struct net_device *dev)100{101 cxgb4_dcb_cleanup_apps(dev);102 cxgb4_dcb_state_init(dev);103}104 105/* update the dcb port support, if version is IEEE then set it to106 * FW_PORT_DCB_VER_IEEE and if DCB_CAP_DCBX_VER_CEE is already set then107 * clear that. and if it is set to CEE then set dcb supported to108 * DCB_CAP_DCBX_VER_CEE & if DCB_CAP_DCBX_VER_IEEE is set, clear it109 */110static inline void cxgb4_dcb_update_support(struct port_dcb_info *dcb)111{112 if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE) {113 if (dcb->supported & DCB_CAP_DCBX_VER_CEE)114 dcb->supported &= ~DCB_CAP_DCBX_VER_CEE;115 dcb->supported |= DCB_CAP_DCBX_VER_IEEE;116 } else if (dcb->dcb_version == FW_PORT_DCB_VER_CEE1D01) {117 if (dcb->supported & DCB_CAP_DCBX_VER_IEEE)118 dcb->supported &= ~DCB_CAP_DCBX_VER_IEEE;119 dcb->supported |= DCB_CAP_DCBX_VER_CEE;120 }121}122 123/* Finite State machine for Data Center Bridging.124 */125void cxgb4_dcb_state_fsm(struct net_device *dev,126 enum cxgb4_dcb_state_input transition_to)127{128 struct port_info *pi = netdev2pinfo(dev);129 struct port_dcb_info *dcb = &pi->dcb;130 struct adapter *adap = pi->adapter;131 enum cxgb4_dcb_state current_state = dcb->state;132 133 netdev_dbg(dev, "%s: State change from %d to %d for %s\n",134 __func__, dcb->state, transition_to, dev->name);135 136 switch (current_state) {137 case CXGB4_DCB_STATE_START: {138 switch (transition_to) {139 case CXGB4_DCB_INPUT_FW_DISABLED: {140 /* we're going to use Host DCB */141 dcb->state = CXGB4_DCB_STATE_HOST;142 dcb->supported = CXGB4_DCBX_HOST_SUPPORT;143 break;144 }145 146 case CXGB4_DCB_INPUT_FW_ENABLED: {147 /* we're going to use Firmware DCB */148 dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;149 dcb->supported = DCB_CAP_DCBX_LLD_MANAGED;150 if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE)151 dcb->supported |= DCB_CAP_DCBX_VER_IEEE;152 else153 dcb->supported |= DCB_CAP_DCBX_VER_CEE;154 break;155 }156 157 case CXGB4_DCB_INPUT_FW_INCOMPLETE: {158 /* expected transition */159 break;160 }161 162 case CXGB4_DCB_INPUT_FW_ALLSYNCED: {163 dcb->state = CXGB4_DCB_STATE_FW_ALLSYNCED;164 break;165 }166 167 default:168 goto bad_state_input;169 }170 break;171 }172 173 case CXGB4_DCB_STATE_FW_INCOMPLETE: {174 if (transition_to != CXGB4_DCB_INPUT_FW_DISABLED) {175 /* during this CXGB4_DCB_STATE_FW_INCOMPLETE state,176 * check if the dcb version is changed (there can be177 * mismatch in default config & the negotiated switch178 * configuration at FW, so update the dcb support179 * accordingly.180 */181 cxgb4_dcb_update_support(dcb);182 }183 switch (transition_to) {184 case CXGB4_DCB_INPUT_FW_ENABLED: {185 /* we're alreaady in firmware DCB mode */186 break;187 }188 189 case CXGB4_DCB_INPUT_FW_INCOMPLETE: {190 /* we're already incomplete */191 break;192 }193 194 case CXGB4_DCB_INPUT_FW_ALLSYNCED: {195 dcb->state = CXGB4_DCB_STATE_FW_ALLSYNCED;196 dcb->enabled = 1;197 linkwatch_fire_event(dev);198 break;199 }200 201 default:202 goto bad_state_input;203 }204 break;205 }206 207 case CXGB4_DCB_STATE_FW_ALLSYNCED: {208 switch (transition_to) {209 case CXGB4_DCB_INPUT_FW_ENABLED: {210 /* we're alreaady in firmware DCB mode */211 break;212 }213 214 case CXGB4_DCB_INPUT_FW_INCOMPLETE: {215 /* We were successfully running with firmware DCB but216 * now it's telling us that it's in an "incomplete217 * state. We need to reset back to a ground state218 * of incomplete.219 */220 cxgb4_dcb_reset(dev);221 dcb->state = CXGB4_DCB_STATE_FW_INCOMPLETE;222 dcb->supported = CXGB4_DCBX_FW_SUPPORT;223 linkwatch_fire_event(dev);224 break;225 }226 227 case CXGB4_DCB_INPUT_FW_ALLSYNCED: {228 /* we're already all sync'ed229 * this is only applicable for IEEE or230 * when another VI already completed negotiaton231 */232 dcb->enabled = 1;233 linkwatch_fire_event(dev);234 break;235 }236 237 default:238 goto bad_state_input;239 }240 break;241 }242 243 case CXGB4_DCB_STATE_HOST: {244 switch (transition_to) {245 case CXGB4_DCB_INPUT_FW_DISABLED: {246 /* we're alreaady in Host DCB mode */247 break;248 }249 250 default:251 goto bad_state_input;252 }253 break;254 }255 256 default:257 goto bad_state_transition;258 }259 return;260 261bad_state_input:262 dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: illegal input symbol %d\n",263 transition_to);264 return;265 266bad_state_transition:267 dev_err(adap->pdev_dev, "cxgb4_dcb_state_fsm: bad state transition, state = %d, input = %d\n",268 current_state, transition_to);269}270 271/* Handle a DCB/DCBX update message from the firmware.272 */273void cxgb4_dcb_handle_fw_update(struct adapter *adap,274 const struct fw_port_cmd *pcmd)275{276 const union fw_port_dcb *fwdcb = &pcmd->u.dcb;277 int port = FW_PORT_CMD_PORTID_G(be32_to_cpu(pcmd->op_to_portid));278 struct net_device *dev = adap->port[adap->chan_map[port]];279 struct port_info *pi = netdev_priv(dev);280 struct port_dcb_info *dcb = &pi->dcb;281 int dcb_type = pcmd->u.dcb.pgid.type;282 int dcb_running_version;283 284 /* Handle Firmware DCB Control messages separately since they drive285 * our state machine.286 */287 if (dcb_type == FW_PORT_DCB_TYPE_CONTROL) {288 enum cxgb4_dcb_state_input input =289 ((pcmd->u.dcb.control.all_syncd_pkd &290 FW_PORT_CMD_ALL_SYNCD_F)291 ? CXGB4_DCB_INPUT_FW_ALLSYNCED292 : CXGB4_DCB_INPUT_FW_INCOMPLETE);293 294 if (dcb->dcb_version != FW_PORT_DCB_VER_UNKNOWN) {295 dcb_running_version = FW_PORT_CMD_DCB_VERSION_G(296 be16_to_cpu(297 pcmd->u.dcb.control.dcb_version_to_app_state));298 if (dcb_running_version == FW_PORT_DCB_VER_CEE1D01 ||299 dcb_running_version == FW_PORT_DCB_VER_IEEE) {300 dcb->dcb_version = dcb_running_version;301 dev_warn(adap->pdev_dev, "Interface %s is running %s\n",302 dev->name,303 dcb_ver_array[dcb->dcb_version]);304 } else {305 dev_warn(adap->pdev_dev,306 "Something screwed up, requested firmware for %s, but firmware returned %s instead\n",307 dcb_ver_array[dcb->dcb_version],308 dcb_ver_array[dcb_running_version]);309 dcb->dcb_version = FW_PORT_DCB_VER_UNKNOWN;310 }311 }312 313 cxgb4_dcb_state_fsm(dev, input);314 return;315 }316 317 /* It's weird, and almost certainly an error, to get Firmware DCB318 * messages when we either haven't been told whether we're going to be319 * doing Host or Firmware DCB; and even worse when we've been told320 * that we're doing Host DCB!321 */322 if (dcb->state == CXGB4_DCB_STATE_START ||323 dcb->state == CXGB4_DCB_STATE_HOST) {324 dev_err(adap->pdev_dev, "Receiving Firmware DCB messages in State %d\n",325 dcb->state);326 return;327 }328 329 /* Now handle the general Firmware DCB update messages ...330 */331 switch (dcb_type) {332 case FW_PORT_DCB_TYPE_PGID:333 dcb->pgid = be32_to_cpu(fwdcb->pgid.pgid);334 dcb->msgs |= CXGB4_DCB_FW_PGID;335 break;336 337 case FW_PORT_DCB_TYPE_PGRATE:338 dcb->pg_num_tcs_supported = fwdcb->pgrate.num_tcs_supported;339 memcpy(dcb->pgrate, &fwdcb->pgrate.pgrate,340 sizeof(dcb->pgrate));341 memcpy(dcb->tsa, &fwdcb->pgrate.tsa,342 sizeof(dcb->tsa));343 dcb->msgs |= CXGB4_DCB_FW_PGRATE;344 if (dcb->msgs & CXGB4_DCB_FW_PGID)345 IEEE_FAUX_SYNC(dev, dcb);346 break;347 348 case FW_PORT_DCB_TYPE_PRIORATE:349 memcpy(dcb->priorate, &fwdcb->priorate.strict_priorate,350 sizeof(dcb->priorate));351 dcb->msgs |= CXGB4_DCB_FW_PRIORATE;352 break;353 354 case FW_PORT_DCB_TYPE_PFC:355 dcb->pfcen = fwdcb->pfc.pfcen;356 dcb->pfc_num_tcs_supported = fwdcb->pfc.max_pfc_tcs;357 dcb->msgs |= CXGB4_DCB_FW_PFC;358 IEEE_FAUX_SYNC(dev, dcb);359 break;360 361 case FW_PORT_DCB_TYPE_APP_ID: {362 const struct fw_port_app_priority *fwap = &fwdcb->app_priority;363 int idx = fwap->idx;364 struct app_priority *ap = &dcb->app_priority[idx];365 366 struct dcb_app app = {367 .protocol = be16_to_cpu(fwap->protocolid),368 };369 int err;370 371 /* Convert from firmware format to relevant format372 * when using app selector373 */374 if (dcb->dcb_version == FW_PORT_DCB_VER_IEEE) {375 app.selector = (fwap->sel_field + 1);376 app.priority = ffs(fwap->user_prio_map) - 1;377 err = dcb_ieee_setapp(dev, &app);378 IEEE_FAUX_SYNC(dev, dcb);379 } else {380 /* Default is CEE */381 app.selector = !!(fwap->sel_field);382 app.priority = fwap->user_prio_map;383 err = dcb_setapp(dev, &app);384 }385 386 if (err)387 dev_err(adap->pdev_dev,388 "Failed DCB Set Application Priority: sel=%d, prot=%d, prio=%d, err=%d\n",389 app.selector, app.protocol, app.priority, -err);390 391 ap->user_prio_map = fwap->user_prio_map;392 ap->sel_field = fwap->sel_field;393 ap->protocolid = be16_to_cpu(fwap->protocolid);394 dcb->msgs |= CXGB4_DCB_FW_APP_ID;395 break;396 }397 398 default:399 dev_err(adap->pdev_dev, "Unknown DCB update type received %x\n",400 dcb_type);401 break;402 }403}404 405/* Data Center Bridging netlink operations.406 */407 408 409/* Get current DCB enabled/disabled state.410 */411static u8 cxgb4_getstate(struct net_device *dev)412{413 struct port_info *pi = netdev2pinfo(dev);414 415 return pi->dcb.enabled;416}417 418/* Set DCB enabled/disabled.419 */420static u8 cxgb4_setstate(struct net_device *dev, u8 enabled)421{422 struct port_info *pi = netdev2pinfo(dev);423 424 /* If DCBx is host-managed, dcb is enabled by outside lldp agents */425 if (pi->dcb.state == CXGB4_DCB_STATE_HOST) {426 pi->dcb.enabled = enabled;427 return 0;428 }429 430 /* Firmware doesn't provide any mechanism to control the DCB state.431 */432 if (enabled != (pi->dcb.state == CXGB4_DCB_STATE_FW_ALLSYNCED))433 return 1;434 435 return 0;436}437 438static void cxgb4_getpgtccfg(struct net_device *dev, int tc,439 u8 *prio_type, u8 *pgid, u8 *bw_per,440 u8 *up_tc_map, int local)441{442 struct fw_port_cmd pcmd;443 struct port_info *pi = netdev2pinfo(dev);444 struct adapter *adap = pi->adapter;445 int err;446 447 *prio_type = *pgid = *bw_per = *up_tc_map = 0;448 449 if (local)450 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);451 else452 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);453 454 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;455 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);456 if (err != FW_PORT_DCB_CFG_SUCCESS) {457 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);458 return;459 }460 *pgid = (be32_to_cpu(pcmd.u.dcb.pgid.pgid) >> (tc * 4)) & 0xf;461 462 if (local)463 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);464 else465 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);466 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;467 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);468 if (err != FW_PORT_DCB_CFG_SUCCESS) {469 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",470 -err);471 return;472 }473 474 *bw_per = pcmd.u.dcb.pgrate.pgrate[*pgid];475 *up_tc_map = (1 << tc);476 477 /* prio_type is link strict */478 if (*pgid != 0xF)479 *prio_type = 0x2;480}481 482static void cxgb4_getpgtccfg_tx(struct net_device *dev, int tc,483 u8 *prio_type, u8 *pgid, u8 *bw_per,484 u8 *up_tc_map)485{486 /* tc 0 is written at MSB position */487 return cxgb4_getpgtccfg(dev, (7 - tc), prio_type, pgid, bw_per,488 up_tc_map, 1);489}490 491 492static void cxgb4_getpgtccfg_rx(struct net_device *dev, int tc,493 u8 *prio_type, u8 *pgid, u8 *bw_per,494 u8 *up_tc_map)495{496 /* tc 0 is written at MSB position */497 return cxgb4_getpgtccfg(dev, (7 - tc), prio_type, pgid, bw_per,498 up_tc_map, 0);499}500 501static void cxgb4_setpgtccfg_tx(struct net_device *dev, int tc,502 u8 prio_type, u8 pgid, u8 bw_per,503 u8 up_tc_map)504{505 struct fw_port_cmd pcmd;506 struct port_info *pi = netdev2pinfo(dev);507 struct adapter *adap = pi->adapter;508 int fw_tc = 7 - tc;509 u32 _pgid;510 int err;511 512 if (pgid == DCB_ATTR_VALUE_UNDEFINED)513 return;514 if (bw_per == DCB_ATTR_VALUE_UNDEFINED)515 return;516 517 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);518 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;519 520 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);521 if (err != FW_PORT_DCB_CFG_SUCCESS) {522 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);523 return;524 }525 526 _pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);527 _pgid &= ~(0xF << (fw_tc * 4));528 _pgid |= pgid << (fw_tc * 4);529 pcmd.u.dcb.pgid.pgid = cpu_to_be32(_pgid);530 531 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);532 533 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);534 if (err != FW_PORT_DCB_CFG_SUCCESS) {535 dev_err(adap->pdev_dev, "DCB write PGID failed with %d\n",536 -err);537 return;538 }539 540 memset(&pcmd, 0, sizeof(struct fw_port_cmd));541 542 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);543 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;544 545 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);546 if (err != FW_PORT_DCB_CFG_SUCCESS) {547 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",548 -err);549 return;550 }551 552 pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per;553 554 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);555 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)556 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY_F);557 558 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);559 if (err != FW_PORT_DCB_CFG_SUCCESS)560 dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n",561 -err);562}563 564static void cxgb4_getpgbwgcfg(struct net_device *dev, int pgid, u8 *bw_per,565 int local)566{567 struct fw_port_cmd pcmd;568 struct port_info *pi = netdev2pinfo(dev);569 struct adapter *adap = pi->adapter;570 int err;571 572 if (local)573 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);574 else575 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);576 577 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;578 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);579 if (err != FW_PORT_DCB_CFG_SUCCESS) {580 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",581 -err);582 return;583 }584 585 *bw_per = pcmd.u.dcb.pgrate.pgrate[pgid];586}587 588static void cxgb4_getpgbwgcfg_tx(struct net_device *dev, int pgid, u8 *bw_per)589{590 return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 1);591}592 593static void cxgb4_getpgbwgcfg_rx(struct net_device *dev, int pgid, u8 *bw_per)594{595 return cxgb4_getpgbwgcfg(dev, pgid, bw_per, 0);596}597 598static void cxgb4_setpgbwgcfg_tx(struct net_device *dev, int pgid,599 u8 bw_per)600{601 struct fw_port_cmd pcmd;602 struct port_info *pi = netdev2pinfo(dev);603 struct adapter *adap = pi->adapter;604 int err;605 606 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);607 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;608 609 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);610 if (err != FW_PORT_DCB_CFG_SUCCESS) {611 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",612 -err);613 return;614 }615 616 pcmd.u.dcb.pgrate.pgrate[pgid] = bw_per;617 618 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);619 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)620 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY_F);621 622 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);623 624 if (err != FW_PORT_DCB_CFG_SUCCESS)625 dev_err(adap->pdev_dev, "DCB write PGRATE failed with %d\n",626 -err);627}628 629/* Return whether the specified Traffic Class Priority has Priority Pause630 * Frames enabled.631 */632static void cxgb4_getpfccfg(struct net_device *dev, int priority, u8 *pfccfg)633{634 struct port_info *pi = netdev2pinfo(dev);635 struct port_dcb_info *dcb = &pi->dcb;636 637 if (!cxgb4_dcb_state_synced(dcb->state) ||638 priority >= CXGB4_MAX_PRIORITY)639 *pfccfg = 0;640 else641 *pfccfg = (pi->dcb.pfcen >> (7 - priority)) & 1;642}643 644/* Enable/disable Priority Pause Frames for the specified Traffic Class645 * Priority.646 */647static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg)648{649 struct fw_port_cmd pcmd;650 struct port_info *pi = netdev2pinfo(dev);651 struct adapter *adap = pi->adapter;652 int err;653 654 if (!cxgb4_dcb_state_synced(pi->dcb.state) ||655 priority >= CXGB4_MAX_PRIORITY)656 return;657 658 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);659 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)660 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY_F);661 662 pcmd.u.dcb.pfc.type = FW_PORT_DCB_TYPE_PFC;663 pcmd.u.dcb.pfc.pfcen = pi->dcb.pfcen;664 665 if (pfccfg)666 pcmd.u.dcb.pfc.pfcen |= (1 << (7 - priority));667 else668 pcmd.u.dcb.pfc.pfcen &= (~(1 << (7 - priority)));669 670 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);671 if (err != FW_PORT_DCB_CFG_SUCCESS) {672 dev_err(adap->pdev_dev, "DCB PFC write failed with %d\n", -err);673 return;674 }675 676 pi->dcb.pfcen = pcmd.u.dcb.pfc.pfcen;677}678 679static u8 cxgb4_setall(struct net_device *dev)680{681 return 0;682}683 684/* Return DCB capabilities.685 */686static u8 cxgb4_getcap(struct net_device *dev, int cap_id, u8 *caps)687{688 struct port_info *pi = netdev2pinfo(dev);689 690 switch (cap_id) {691 case DCB_CAP_ATTR_PG:692 case DCB_CAP_ATTR_PFC:693 *caps = true;694 break;695 696 case DCB_CAP_ATTR_PG_TCS:697 /* 8 priorities for PG represented by bitmap */698 *caps = 0x80;699 break;700 701 case DCB_CAP_ATTR_PFC_TCS:702 /* 8 priorities for PFC represented by bitmap */703 *caps = 0x80;704 break;705 706 case DCB_CAP_ATTR_GSP:707 *caps = true;708 break;709 710 case DCB_CAP_ATTR_UP2TC:711 case DCB_CAP_ATTR_BCN:712 *caps = false;713 break;714 715 case DCB_CAP_ATTR_DCBX:716 *caps = pi->dcb.supported;717 break;718 719 default:720 *caps = false;721 }722 723 return 0;724}725 726/* Return the number of Traffic Classes for the indicated Traffic Class ID.727 */728static int cxgb4_getnumtcs(struct net_device *dev, int tcs_id, u8 *num)729{730 struct port_info *pi = netdev2pinfo(dev);731 732 switch (tcs_id) {733 case DCB_NUMTCS_ATTR_PG:734 if (pi->dcb.msgs & CXGB4_DCB_FW_PGRATE)735 *num = pi->dcb.pg_num_tcs_supported;736 else737 *num = 0x8;738 break;739 740 case DCB_NUMTCS_ATTR_PFC:741 *num = 0x8;742 break;743 744 default:745 return -EINVAL;746 }747 748 return 0;749}750 751/* Set the number of Traffic Classes supported for the indicated Traffic Class752 * ID.753 */754static int cxgb4_setnumtcs(struct net_device *dev, int tcs_id, u8 num)755{756 /* Setting the number of Traffic Classes isn't supported.757 */758 return -ENOSYS;759}760 761/* Return whether Priority Flow Control is enabled. */762static u8 cxgb4_getpfcstate(struct net_device *dev)763{764 struct port_info *pi = netdev2pinfo(dev);765 766 if (!cxgb4_dcb_state_synced(pi->dcb.state))767 return false;768 769 return pi->dcb.pfcen != 0;770}771 772/* Enable/disable Priority Flow Control. */773static void cxgb4_setpfcstate(struct net_device *dev, u8 state)774{775 /* We can't enable/disable Priority Flow Control but we also can't776 * return an error ...777 */778}779 780/* Return the Application User Priority Map associated with the specified781 * Application ID.782 */783static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id,784 int peer)785{786 struct port_info *pi = netdev2pinfo(dev);787 struct adapter *adap = pi->adapter;788 int i;789 790 if (!cxgb4_dcb_state_synced(pi->dcb.state))791 return 0;792 793 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {794 struct fw_port_cmd pcmd;795 int err;796 797 if (peer)798 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);799 else800 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);801 802 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;803 pcmd.u.dcb.app_priority.idx = i;804 805 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);806 if (err != FW_PORT_DCB_CFG_SUCCESS) {807 dev_err(adap->pdev_dev, "DCB APP read failed with %d\n",808 -err);809 return err;810 }811 if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id)812 if (pcmd.u.dcb.app_priority.sel_field == app_idtype)813 return pcmd.u.dcb.app_priority.user_prio_map;814 815 /* exhausted app list */816 if (!pcmd.u.dcb.app_priority.protocolid)817 break;818 }819 820 return -EEXIST;821}822 823/* Return the Application User Priority Map associated with the specified824 * Application ID.825 */826static int cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id)827{828 /* Convert app_idtype to firmware format before querying */829 return __cxgb4_getapp(dev, app_idtype == DCB_APP_IDTYPE_ETHTYPE ?830 app_idtype : 3, app_id, 0);831}832 833/* Write a new Application User Priority Map for the specified Application ID834 */835static int __cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id,836 u8 app_prio)837{838 struct fw_port_cmd pcmd;839 struct port_info *pi = netdev2pinfo(dev);840 struct adapter *adap = pi->adapter;841 int i, err;842 843 844 if (!cxgb4_dcb_state_synced(pi->dcb.state))845 return -EINVAL;846 847 /* DCB info gets thrown away on link up */848 if (!netif_carrier_ok(dev))849 return -ENOLINK;850 851 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {852 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);853 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;854 pcmd.u.dcb.app_priority.idx = i;855 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);856 857 if (err != FW_PORT_DCB_CFG_SUCCESS) {858 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",859 -err);860 return err;861 }862 if (be16_to_cpu(pcmd.u.dcb.app_priority.protocolid) == app_id) {863 /* overwrite existing app table */864 pcmd.u.dcb.app_priority.protocolid = 0;865 break;866 }867 /* find first empty slot */868 if (!pcmd.u.dcb.app_priority.protocolid)869 break;870 }871 872 if (i == CXGB4_MAX_DCBX_APP_SUPPORTED) {873 /* no empty slots available */874 dev_err(adap->pdev_dev, "DCB app table full\n");875 return -EBUSY;876 }877 878 /* write out new app table entry */879 INIT_PORT_DCB_WRITE_CMD(pcmd, pi->port_id);880 if (pi->dcb.state == CXGB4_DCB_STATE_HOST)881 pcmd.op_to_portid |= cpu_to_be32(FW_PORT_CMD_APPLY_F);882 883 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;884 pcmd.u.dcb.app_priority.protocolid = cpu_to_be16(app_id);885 pcmd.u.dcb.app_priority.sel_field = app_idtype;886 pcmd.u.dcb.app_priority.user_prio_map = app_prio;887 pcmd.u.dcb.app_priority.idx = i;888 889 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);890 if (err != FW_PORT_DCB_CFG_SUCCESS) {891 dev_err(adap->pdev_dev, "DCB app table write failed with %d\n",892 -err);893 return err;894 }895 896 return 0;897}898 899/* Priority for CEE inside dcb_app is bitmask, with 0 being an invalid value */900static int cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id,901 u8 app_prio)902{903 int ret;904 struct dcb_app app = {905 .selector = app_idtype,906 .protocol = app_id,907 .priority = app_prio,908 };909 910 if (app_idtype != DCB_APP_IDTYPE_ETHTYPE &&911 app_idtype != DCB_APP_IDTYPE_PORTNUM)912 return -EINVAL;913 914 /* Convert app_idtype to a format that firmware understands */915 ret = __cxgb4_setapp(dev, app_idtype == DCB_APP_IDTYPE_ETHTYPE ?916 app_idtype : 3, app_id, app_prio);917 if (ret)918 return ret;919 920 return dcb_setapp(dev, &app);921}922 923/* Return whether IEEE Data Center Bridging has been negotiated.924 */925static inline int926cxgb4_ieee_negotiation_complete(struct net_device *dev,927 enum cxgb4_dcb_fw_msgs dcb_subtype)928{929 struct port_info *pi = netdev2pinfo(dev);930 struct port_dcb_info *dcb = &pi->dcb;931 932 if (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED)933 if (dcb_subtype && !(dcb->msgs & dcb_subtype))934 return 0;935 936 return (cxgb4_dcb_state_synced(dcb->state) &&937 (dcb->supported & DCB_CAP_DCBX_VER_IEEE));938}939 940static int cxgb4_ieee_read_ets(struct net_device *dev, struct ieee_ets *ets,941 int local)942{943 struct port_info *pi = netdev2pinfo(dev);944 struct port_dcb_info *dcb = &pi->dcb;945 struct adapter *adap = pi->adapter;946 uint32_t tc_info;947 struct fw_port_cmd pcmd;948 int i, bwg, err;949 950 if (!(dcb->msgs & (CXGB4_DCB_FW_PGID | CXGB4_DCB_FW_PGRATE)))951 return 0;952 953 ets->ets_cap = dcb->pg_num_tcs_supported;954 955 if (local) {956 ets->willing = 1;957 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);958 } else {959 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);960 }961 962 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;963 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);964 if (err != FW_PORT_DCB_CFG_SUCCESS) {965 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);966 return err;967 }968 969 tc_info = be32_to_cpu(pcmd.u.dcb.pgid.pgid);970 971 if (local)972 INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);973 else974 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);975 976 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;977 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);978 if (err != FW_PORT_DCB_CFG_SUCCESS) {979 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",980 -err);981 return err;982 }983 984 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {985 bwg = (tc_info >> ((7 - i) * 4)) & 0xF;986 ets->prio_tc[i] = bwg;987 ets->tc_tx_bw[i] = pcmd.u.dcb.pgrate.pgrate[i];988 ets->tc_rx_bw[i] = ets->tc_tx_bw[i];989 ets->tc_tsa[i] = pcmd.u.dcb.pgrate.tsa[i];990 }991 992 return 0;993}994 995static int cxgb4_ieee_get_ets(struct net_device *dev, struct ieee_ets *ets)996{997 return cxgb4_ieee_read_ets(dev, ets, 1);998}999 1000/* We reuse this for peer PFC as well, as we can't have it enabled one way */1001static int cxgb4_ieee_get_pfc(struct net_device *dev, struct ieee_pfc *pfc)1002{1003 struct port_info *pi = netdev2pinfo(dev);1004 struct port_dcb_info *dcb = &pi->dcb;1005 1006 memset(pfc, 0, sizeof(struct ieee_pfc));1007 1008 if (!(dcb->msgs & CXGB4_DCB_FW_PFC))1009 return 0;1010 1011 pfc->pfc_cap = dcb->pfc_num_tcs_supported;1012 pfc->pfc_en = bitswap_1(dcb->pfcen);1013 1014 return 0;1015}1016 1017static int cxgb4_ieee_peer_ets(struct net_device *dev, struct ieee_ets *ets)1018{1019 return cxgb4_ieee_read_ets(dev, ets, 0);1020}1021 1022/* Fill in the Application User Priority Map associated with the1023 * specified Application.1024 * Priority for IEEE dcb_app is an integer, with 0 being a valid value1025 */1026static int cxgb4_ieee_getapp(struct net_device *dev, struct dcb_app *app)1027{1028 int prio;1029 1030 if (!cxgb4_ieee_negotiation_complete(dev, CXGB4_DCB_FW_APP_ID))1031 return -EINVAL;1032 if (!(app->selector && app->protocol))1033 return -EINVAL;1034 1035 /* Try querying firmware first, use firmware format */1036 prio = __cxgb4_getapp(dev, app->selector - 1, app->protocol, 0);1037 1038 if (prio < 0)1039 prio = dcb_ieee_getapp_mask(dev, app);1040 1041 app->priority = ffs(prio) - 1;1042 return 0;1043}1044 1045/* Write a new Application User Priority Map for the specified Application ID.1046 * Priority for IEEE dcb_app is an integer, with 0 being a valid value1047 */1048static int cxgb4_ieee_setapp(struct net_device *dev, struct dcb_app *app)1049{1050 int ret;1051 1052 if (!cxgb4_ieee_negotiation_complete(dev, CXGB4_DCB_FW_APP_ID))1053 return -EINVAL;1054 if (!(app->selector && app->protocol))1055 return -EINVAL;1056 1057 if (!(app->selector > IEEE_8021QAZ_APP_SEL_ETHERTYPE &&1058 app->selector < IEEE_8021QAZ_APP_SEL_ANY))1059 return -EINVAL;1060 1061 /* change selector to a format that firmware understands */1062 ret = __cxgb4_setapp(dev, app->selector - 1, app->protocol,1063 (1 << app->priority));1064 if (ret)1065 return ret;1066 1067 return dcb_ieee_setapp(dev, app);1068}1069 1070/* Return our DCBX parameters.1071 */1072static u8 cxgb4_getdcbx(struct net_device *dev)1073{1074 struct port_info *pi = netdev2pinfo(dev);1075 1076 /* This is already set by cxgb4_set_dcb_caps, so just return it */1077 return pi->dcb.supported;1078}1079 1080/* Set our DCBX parameters.1081 */1082static u8 cxgb4_setdcbx(struct net_device *dev, u8 dcb_request)1083{1084 struct port_info *pi = netdev2pinfo(dev);1085 1086 /* Filter out requests which exceed our capabilities.1087 */1088 if ((dcb_request & (CXGB4_DCBX_FW_SUPPORT | CXGB4_DCBX_HOST_SUPPORT))1089 != dcb_request)1090 return 1;1091 1092 /* Can't enable DCB if we haven't successfully negotiated it.1093 */1094 if (!cxgb4_dcb_state_synced(pi->dcb.state))1095 return 1;1096 1097 /* There's currently no mechanism to allow for the firmware DCBX1098 * negotiation to be changed from the Host Driver. If the caller1099 * requests exactly the same parameters that we already have then1100 * we'll allow them to be successfully "set" ...1101 */1102 if (dcb_request != pi->dcb.supported)1103 return 1;1104 1105 pi->dcb.supported = dcb_request;1106 return 0;1107}1108 1109static int cxgb4_getpeer_app(struct net_device *dev,1110 struct dcb_peer_app_info *info, u16 *app_count)1111{1112 struct fw_port_cmd pcmd;1113 struct port_info *pi = netdev2pinfo(dev);1114 struct adapter *adap = pi->adapter;1115 int i, err = 0;1116 1117 if (!cxgb4_dcb_state_synced(pi->dcb.state))1118 return 1;1119 1120 info->willing = 0;1121 info->error = 0;1122 1123 *app_count = 0;1124 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {1125 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);1126 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;1127 pcmd.u.dcb.app_priority.idx = *app_count;1128 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);1129 1130 if (err != FW_PORT_DCB_CFG_SUCCESS) {1131 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",1132 -err);1133 return err;1134 }1135 1136 /* find first empty slot */1137 if (!pcmd.u.dcb.app_priority.protocolid)1138 break;1139 }1140 *app_count = i;1141 return err;1142}1143 1144static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table)1145{1146 struct fw_port_cmd pcmd;1147 struct port_info *pi = netdev2pinfo(dev);1148 struct adapter *adap = pi->adapter;1149 int i, err = 0;1150 1151 if (!cxgb4_dcb_state_synced(pi->dcb.state))1152 return 1;1153 1154 for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) {1155 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);1156 pcmd.u.dcb.app_priority.type = FW_PORT_DCB_TYPE_APP_ID;1157 pcmd.u.dcb.app_priority.idx = i;1158 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);1159 1160 if (err != FW_PORT_DCB_CFG_SUCCESS) {1161 dev_err(adap->pdev_dev, "DCB app table read failed with %d\n",1162 -err);1163 return err;1164 }1165 1166 /* find first empty slot */1167 if (!pcmd.u.dcb.app_priority.protocolid)1168 break;1169 1170 table[i].selector = (pcmd.u.dcb.app_priority.sel_field + 1);1171 table[i].protocol =1172 be16_to_cpu(pcmd.u.dcb.app_priority.protocolid);1173 table[i].priority =1174 ffs(pcmd.u.dcb.app_priority.user_prio_map) - 1;1175 }1176 return err;1177}1178 1179/* Return Priority Group information.1180 */1181static int cxgb4_cee_peer_getpg(struct net_device *dev, struct cee_pg *pg)1182{1183 struct fw_port_cmd pcmd;1184 struct port_info *pi = netdev2pinfo(dev);1185 struct adapter *adap = pi->adapter;1186 u32 pgid;1187 int i, err;1188 1189 /* We're always "willing" -- the Switch Fabric always dictates the1190 * DCBX parameters to us.1191 */1192 pg->willing = true;1193 1194 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);1195 pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;1196 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);1197 if (err != FW_PORT_DCB_CFG_SUCCESS) {1198 dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);1199 return err;1200 }1201 pgid = be32_to_cpu(pcmd.u.dcb.pgid.pgid);1202 1203 for (i = 0; i < CXGB4_MAX_PRIORITY; i++)1204 pg->prio_pg[7 - i] = (pgid >> (i * 4)) & 0xF;1205 1206 INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);1207 pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;1208 err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);1209 if (err != FW_PORT_DCB_CFG_SUCCESS) {1210 dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",1211 -err);1212 return err;1213 }1214 1215 for (i = 0; i < CXGB4_MAX_PRIORITY; i++)1216 pg->pg_bw[i] = pcmd.u.dcb.pgrate.pgrate[i];1217 1218 pg->tcs_supported = pcmd.u.dcb.pgrate.num_tcs_supported;1219 1220 return 0;1221}1222 1223/* Return Priority Flow Control information.1224 */1225static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc)1226{1227 struct port_info *pi = netdev2pinfo(dev);1228 1229 cxgb4_getnumtcs(dev, DCB_NUMTCS_ATTR_PFC, &(pfc->tcs_supported));1230 1231 /* Firmware sends this to us in a formwat that is a bit flipped version1232 * of spec, correct it before we send it to host. This is taken care of1233 * by bit shifting in other uses of pfcen1234 */1235 pfc->pfc_en = bitswap_1(pi->dcb.pfcen);1236 1237 pfc->tcs_supported = pi->dcb.pfc_num_tcs_supported;1238 1239 return 0;1240}1241 1242const struct dcbnl_rtnl_ops cxgb4_dcb_ops = {1243 .ieee_getets = cxgb4_ieee_get_ets,1244 .ieee_getpfc = cxgb4_ieee_get_pfc,1245 .ieee_getapp = cxgb4_ieee_getapp,1246 .ieee_setapp = cxgb4_ieee_setapp,1247 .ieee_peer_getets = cxgb4_ieee_peer_ets,1248 .ieee_peer_getpfc = cxgb4_ieee_get_pfc,1249 1250 /* CEE std */1251 .getstate = cxgb4_getstate,1252 .setstate = cxgb4_setstate,1253 .getpgtccfgtx = cxgb4_getpgtccfg_tx,1254 .getpgbwgcfgtx = cxgb4_getpgbwgcfg_tx,1255 .getpgtccfgrx = cxgb4_getpgtccfg_rx,1256 .getpgbwgcfgrx = cxgb4_getpgbwgcfg_rx,1257 .setpgtccfgtx = cxgb4_setpgtccfg_tx,1258 .setpgbwgcfgtx = cxgb4_setpgbwgcfg_tx,1259 .setpfccfg = cxgb4_setpfccfg,1260 .getpfccfg = cxgb4_getpfccfg,1261 .setall = cxgb4_setall,1262 .getcap = cxgb4_getcap,1263 .getnumtcs = cxgb4_getnumtcs,1264 .setnumtcs = cxgb4_setnumtcs,1265 .getpfcstate = cxgb4_getpfcstate,1266 .setpfcstate = cxgb4_setpfcstate,1267 .getapp = cxgb4_getapp,1268 .setapp = cxgb4_setapp,1269 1270 /* DCBX configuration */1271 .getdcbx = cxgb4_getdcbx,1272 .setdcbx = cxgb4_setdcbx,1273 1274 /* peer apps */1275 .peer_getappinfo = cxgb4_getpeer_app,1276 .peer_getapptable = cxgb4_getpeerapp_tbl,1277 1278 /* CEE peer */1279 .cee_peer_getpg = cxgb4_cee_peer_getpg,1280 .cee_peer_getpfc = cxgb4_cee_peer_getpfc,1281};1282