0001
0002
0003
0004
0005
0006
0007 #include <linux/module.h>
0008 #include <linux/phy/phy.h>
0009
0010 #include "sparx5_main_regs.h"
0011 #include "sparx5_main.h"
0012 #include "sparx5_port.h"
0013
0014 #define SPX5_ETYPE_TAG_C 0x8100
0015 #define SPX5_ETYPE_TAG_S 0x88a8
0016
0017 #define SPX5_WAIT_US 1000
0018 #define SPX5_WAIT_MAX_US 2000
0019
0020 enum port_error {
0021 SPX5_PERR_SPEED,
0022 SPX5_PERR_IFTYPE,
0023 };
0024
0025 #define PAUSE_DISCARD 0xC
0026 #define ETH_MAXLEN (ETH_DATA_LEN + ETH_HLEN + ETH_FCS_LEN)
0027
0028 static void decode_sgmii_word(u16 lp_abil, struct sparx5_port_status *status)
0029 {
0030 status->an_complete = true;
0031 if (!(lp_abil & LPA_SGMII_LINK)) {
0032 status->link = false;
0033 return;
0034 }
0035
0036 switch (lp_abil & LPA_SGMII_SPD_MASK) {
0037 case LPA_SGMII_10:
0038 status->speed = SPEED_10;
0039 break;
0040 case LPA_SGMII_100:
0041 status->speed = SPEED_100;
0042 break;
0043 case LPA_SGMII_1000:
0044 status->speed = SPEED_1000;
0045 break;
0046 default:
0047 status->link = false;
0048 return;
0049 }
0050 if (lp_abil & LPA_SGMII_FULL_DUPLEX)
0051 status->duplex = DUPLEX_FULL;
0052 else
0053 status->duplex = DUPLEX_HALF;
0054 }
0055
0056 static void decode_cl37_word(u16 lp_abil, uint16_t ld_abil, struct sparx5_port_status *status)
0057 {
0058 status->link = !(lp_abil & ADVERTISE_RFAULT) && status->link;
0059 status->an_complete = true;
0060 status->duplex = (ADVERTISE_1000XFULL & lp_abil) ?
0061 DUPLEX_FULL : DUPLEX_UNKNOWN;
0062
0063 if ((ld_abil & ADVERTISE_1000XPAUSE) &&
0064 (lp_abil & ADVERTISE_1000XPAUSE)) {
0065 status->pause = MLO_PAUSE_RX | MLO_PAUSE_TX;
0066 } else if ((ld_abil & ADVERTISE_1000XPSE_ASYM) &&
0067 (lp_abil & ADVERTISE_1000XPSE_ASYM)) {
0068 status->pause |= (lp_abil & ADVERTISE_1000XPAUSE) ?
0069 MLO_PAUSE_TX : 0;
0070 status->pause |= (ld_abil & ADVERTISE_1000XPAUSE) ?
0071 MLO_PAUSE_RX : 0;
0072 } else {
0073 status->pause = MLO_PAUSE_NONE;
0074 }
0075 }
0076
0077 static int sparx5_get_dev2g5_status(struct sparx5 *sparx5,
0078 struct sparx5_port *port,
0079 struct sparx5_port_status *status)
0080 {
0081 u32 portno = port->portno;
0082 u16 lp_adv, ld_adv;
0083 u32 value;
0084
0085
0086 value = spx5_rd(sparx5, DEV2G5_PCS1G_STICKY(portno));
0087 status->link_down = DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY_GET(value);
0088 if (status->link_down)
0089 spx5_wr(value, sparx5, DEV2G5_PCS1G_STICKY(portno));
0090
0091
0092 value = spx5_rd(sparx5, DEV2G5_PCS1G_LINK_STATUS(portno));
0093 status->link = DEV2G5_PCS1G_LINK_STATUS_LINK_STATUS_GET(value) &&
0094 DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS_GET(value);
0095
0096 if (port->conf.portmode == PHY_INTERFACE_MODE_1000BASEX)
0097 status->speed = SPEED_1000;
0098 else if (port->conf.portmode == PHY_INTERFACE_MODE_2500BASEX)
0099 status->speed = SPEED_2500;
0100
0101 status->duplex = DUPLEX_FULL;
0102
0103
0104 value = spx5_rd(sparx5, DEV2G5_PCS1G_ANEG_STATUS(portno));
0105
0106
0107 if (DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE_GET(value)) {
0108 lp_adv = DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY_GET(value);
0109 if (port->conf.portmode == PHY_INTERFACE_MODE_SGMII) {
0110 decode_sgmii_word(lp_adv, status);
0111 } else {
0112 value = spx5_rd(sparx5, DEV2G5_PCS1G_ANEG_CFG(portno));
0113 ld_adv = DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY_GET(value);
0114 decode_cl37_word(lp_adv, ld_adv, status);
0115 }
0116 }
0117 return 0;
0118 }
0119
0120 static int sparx5_get_sfi_status(struct sparx5 *sparx5,
0121 struct sparx5_port *port,
0122 struct sparx5_port_status *status)
0123 {
0124 bool high_speed_dev = sparx5_is_baser(port->conf.portmode);
0125 u32 portno = port->portno;
0126 u32 value, dev, tinst;
0127 void __iomem *inst;
0128
0129 if (!high_speed_dev) {
0130 netdev_err(port->ndev, "error: low speed and SFI mode\n");
0131 return -EINVAL;
0132 }
0133
0134 dev = sparx5_to_high_dev(portno);
0135 tinst = sparx5_port_dev_index(portno);
0136 inst = spx5_inst_get(sparx5, dev, tinst);
0137
0138 value = spx5_inst_rd(inst, DEV10G_MAC_TX_MONITOR_STICKY(0));
0139 if (value != DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY) {
0140
0141 status->link_down = 1;
0142 spx5_inst_wr(0xffffffff, inst, DEV10G_MAC_TX_MONITOR_STICKY(0));
0143 value = spx5_inst_rd(inst, DEV10G_MAC_TX_MONITOR_STICKY(0));
0144 }
0145 status->link = (value == DEV10G_MAC_TX_MONITOR_STICKY_IDLE_STATE_STICKY);
0146 status->duplex = DUPLEX_FULL;
0147 if (port->conf.portmode == PHY_INTERFACE_MODE_5GBASER)
0148 status->speed = SPEED_5000;
0149 else if (port->conf.portmode == PHY_INTERFACE_MODE_10GBASER)
0150 status->speed = SPEED_10000;
0151 else
0152 status->speed = SPEED_25000;
0153
0154 return 0;
0155 }
0156
0157
0158
0159 int sparx5_get_port_status(struct sparx5 *sparx5,
0160 struct sparx5_port *port,
0161 struct sparx5_port_status *status)
0162 {
0163 memset(status, 0, sizeof(*status));
0164 status->speed = port->conf.speed;
0165 if (port->conf.power_down) {
0166 status->link = false;
0167 return 0;
0168 }
0169 switch (port->conf.portmode) {
0170 case PHY_INTERFACE_MODE_SGMII:
0171 case PHY_INTERFACE_MODE_QSGMII:
0172 case PHY_INTERFACE_MODE_1000BASEX:
0173 case PHY_INTERFACE_MODE_2500BASEX:
0174 return sparx5_get_dev2g5_status(sparx5, port, status);
0175 case PHY_INTERFACE_MODE_5GBASER:
0176 case PHY_INTERFACE_MODE_10GBASER:
0177 case PHY_INTERFACE_MODE_25GBASER:
0178 return sparx5_get_sfi_status(sparx5, port, status);
0179 case PHY_INTERFACE_MODE_NA:
0180 return 0;
0181 default:
0182 netdev_err(port->ndev, "Status not supported");
0183 return -ENODEV;
0184 }
0185 return 0;
0186 }
0187
0188 static int sparx5_port_error(struct sparx5_port *port,
0189 struct sparx5_port_config *conf,
0190 enum port_error errtype)
0191 {
0192 switch (errtype) {
0193 case SPX5_PERR_SPEED:
0194 netdev_err(port->ndev,
0195 "Interface does not support speed: %u: for %s\n",
0196 conf->speed, phy_modes(conf->portmode));
0197 break;
0198 case SPX5_PERR_IFTYPE:
0199 netdev_err(port->ndev,
0200 "Switch port does not support interface type: %s\n",
0201 phy_modes(conf->portmode));
0202 break;
0203 default:
0204 netdev_err(port->ndev,
0205 "Interface configuration error\n");
0206 }
0207
0208 return -EINVAL;
0209 }
0210
0211 static int sparx5_port_verify_speed(struct sparx5 *sparx5,
0212 struct sparx5_port *port,
0213 struct sparx5_port_config *conf)
0214 {
0215 if ((sparx5_port_is_2g5(port->portno) &&
0216 conf->speed > SPEED_2500) ||
0217 (sparx5_port_is_5g(port->portno) &&
0218 conf->speed > SPEED_5000) ||
0219 (sparx5_port_is_10g(port->portno) &&
0220 conf->speed > SPEED_10000))
0221 return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
0222
0223 switch (conf->portmode) {
0224 case PHY_INTERFACE_MODE_NA:
0225 return -EINVAL;
0226 case PHY_INTERFACE_MODE_1000BASEX:
0227 if (conf->speed != SPEED_1000 ||
0228 sparx5_port_is_2g5(port->portno))
0229 return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
0230 if (sparx5_port_is_2g5(port->portno))
0231 return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE);
0232 break;
0233 case PHY_INTERFACE_MODE_2500BASEX:
0234 if (conf->speed != SPEED_2500 ||
0235 sparx5_port_is_2g5(port->portno))
0236 return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
0237 break;
0238 case PHY_INTERFACE_MODE_QSGMII:
0239 if (port->portno > 47)
0240 return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE);
0241 fallthrough;
0242 case PHY_INTERFACE_MODE_SGMII:
0243 if (conf->speed != SPEED_1000 &&
0244 conf->speed != SPEED_100 &&
0245 conf->speed != SPEED_10 &&
0246 conf->speed != SPEED_2500)
0247 return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
0248 break;
0249 case PHY_INTERFACE_MODE_5GBASER:
0250 case PHY_INTERFACE_MODE_10GBASER:
0251 case PHY_INTERFACE_MODE_25GBASER:
0252 if ((conf->speed != SPEED_5000 &&
0253 conf->speed != SPEED_10000 &&
0254 conf->speed != SPEED_25000))
0255 return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
0256 break;
0257 default:
0258 return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE);
0259 }
0260 return 0;
0261 }
0262
0263 static bool sparx5_dev_change(struct sparx5 *sparx5,
0264 struct sparx5_port *port,
0265 struct sparx5_port_config *conf)
0266 {
0267 return sparx5_is_baser(port->conf.portmode) ^
0268 sparx5_is_baser(conf->portmode);
0269 }
0270
0271 static int sparx5_port_flush_poll(struct sparx5 *sparx5, u32 portno)
0272 {
0273 u32 value, resource, prio, delay_cnt = 0;
0274 bool poll_src = true;
0275 char *mem = "";
0276
0277
0278
0279
0280
0281
0282 while (1) {
0283 bool empty = true;
0284
0285 for (resource = 0; resource < (poll_src ? 2 : 1); resource++) {
0286 u32 base;
0287
0288 base = (resource == 0 ? 2048 : 0) + SPX5_PRIOS * portno;
0289 for (prio = 0; prio < SPX5_PRIOS; prio++) {
0290 value = spx5_rd(sparx5,
0291 QRES_RES_STAT(base + prio));
0292 if (value) {
0293 mem = resource == 0 ?
0294 "DST-MEM" : "SRC-MEM";
0295 empty = false;
0296 }
0297 }
0298 }
0299
0300 if (empty)
0301 break;
0302
0303 if (delay_cnt++ == 2000) {
0304 dev_err(sparx5->dev,
0305 "Flush timeout port %u. %s queue not empty\n",
0306 portno, mem);
0307 return -EINVAL;
0308 }
0309
0310 usleep_range(SPX5_WAIT_US, SPX5_WAIT_MAX_US);
0311 }
0312 return 0;
0313 }
0314
0315 static int sparx5_port_disable(struct sparx5 *sparx5, struct sparx5_port *port, bool high_spd_dev)
0316 {
0317 u32 tinst = high_spd_dev ?
0318 sparx5_port_dev_index(port->portno) : port->portno;
0319 u32 dev = high_spd_dev ?
0320 sparx5_to_high_dev(port->portno) : TARGET_DEV2G5;
0321 void __iomem *devinst = spx5_inst_get(sparx5, dev, tinst);
0322 u32 spd = port->conf.speed;
0323 u32 spd_prm;
0324 int err;
0325
0326 if (high_spd_dev) {
0327
0328 spx5_inst_rmw(DEV10G_DEV_RST_CTRL_PCS_RX_RST,
0329 DEV10G_DEV_RST_CTRL_PCS_RX_RST,
0330 devinst,
0331 DEV10G_DEV_RST_CTRL(0));
0332
0333
0334 spx5_inst_rmw(0,
0335 DEV10G_MAC_ENA_CFG_RX_ENA,
0336 devinst,
0337 DEV10G_MAC_ENA_CFG(0));
0338 } else {
0339
0340 spx5_inst_rmw(DEV2G5_DEV_RST_CTRL_PCS_RX_RST,
0341 DEV2G5_DEV_RST_CTRL_PCS_RX_RST,
0342 devinst,
0343 DEV2G5_DEV_RST_CTRL(0));
0344
0345 spx5_inst_rmw(0,
0346 DEV2G5_MAC_ENA_CFG_RX_ENA,
0347 devinst,
0348 DEV2G5_MAC_ENA_CFG(0));
0349 }
0350
0351 spx5_rmw(0,
0352 QFWD_SWITCH_PORT_MODE_PORT_ENA,
0353 sparx5,
0354 QFWD_SWITCH_PORT_MODE(port->portno));
0355
0356
0357 spx5_rmw(HSCH_PORT_MODE_DEQUEUE_DIS,
0358 HSCH_PORT_MODE_DEQUEUE_DIS,
0359 sparx5,
0360 HSCH_PORT_MODE(port->portno));
0361
0362
0363 spx5_rmw(QSYS_PAUSE_CFG_PAUSE_STOP_SET(0xFFF - 1),
0364 QSYS_PAUSE_CFG_PAUSE_STOP,
0365 sparx5,
0366 QSYS_PAUSE_CFG(port->portno));
0367
0368 spd_prm = spd == SPEED_10 ? 1000 : spd == SPEED_100 ? 100 : 10;
0369
0370 usleep_range(8 * spd_prm, 10 * spd_prm);
0371
0372
0373 spx5_rmw(HSCH_FLUSH_CTRL_FLUSH_PORT_SET(port->portno) |
0374 HSCH_FLUSH_CTRL_FLUSH_DST_SET(1) |
0375 HSCH_FLUSH_CTRL_FLUSH_SRC_SET(1) |
0376 HSCH_FLUSH_CTRL_FLUSH_ENA_SET(1),
0377 HSCH_FLUSH_CTRL_FLUSH_PORT |
0378 HSCH_FLUSH_CTRL_FLUSH_DST |
0379 HSCH_FLUSH_CTRL_FLUSH_SRC |
0380 HSCH_FLUSH_CTRL_FLUSH_ENA,
0381 sparx5,
0382 HSCH_FLUSH_CTRL);
0383
0384
0385 spx5_rmw(0,
0386 HSCH_PORT_MODE_DEQUEUE_DIS,
0387 sparx5,
0388 HSCH_PORT_MODE(port->portno));
0389
0390
0391 err = sparx5_port_flush_poll(sparx5, port->portno);
0392 if (err)
0393 return err;
0394
0395
0396 if (high_spd_dev) {
0397 spx5_inst_rmw(DEV10G_DEV_RST_CTRL_PCS_TX_RST_SET(1) |
0398 DEV10G_DEV_RST_CTRL_MAC_RX_RST_SET(1) |
0399 DEV10G_DEV_RST_CTRL_MAC_TX_RST_SET(1),
0400 DEV10G_DEV_RST_CTRL_PCS_TX_RST |
0401 DEV10G_DEV_RST_CTRL_MAC_RX_RST |
0402 DEV10G_DEV_RST_CTRL_MAC_TX_RST,
0403 devinst,
0404 DEV10G_DEV_RST_CTRL(0));
0405
0406 } else {
0407 spx5_inst_rmw(DEV2G5_DEV_RST_CTRL_SPEED_SEL_SET(3) |
0408 DEV2G5_DEV_RST_CTRL_PCS_TX_RST_SET(1) |
0409 DEV2G5_DEV_RST_CTRL_PCS_RX_RST_SET(1) |
0410 DEV2G5_DEV_RST_CTRL_MAC_TX_RST_SET(1) |
0411 DEV2G5_DEV_RST_CTRL_MAC_RX_RST_SET(1),
0412 DEV2G5_DEV_RST_CTRL_SPEED_SEL |
0413 DEV2G5_DEV_RST_CTRL_PCS_TX_RST |
0414 DEV2G5_DEV_RST_CTRL_PCS_RX_RST |
0415 DEV2G5_DEV_RST_CTRL_MAC_TX_RST |
0416 DEV2G5_DEV_RST_CTRL_MAC_RX_RST,
0417 devinst,
0418 DEV2G5_DEV_RST_CTRL(0));
0419 }
0420
0421 spx5_rmw(HSCH_FLUSH_CTRL_FLUSH_PORT_SET(port->portno) |
0422 HSCH_FLUSH_CTRL_FLUSH_ENA_SET(0),
0423 HSCH_FLUSH_CTRL_FLUSH_PORT |
0424 HSCH_FLUSH_CTRL_FLUSH_ENA,
0425 sparx5,
0426 HSCH_FLUSH_CTRL);
0427
0428 if (high_spd_dev) {
0429 u32 pcs = sparx5_to_pcs_dev(port->portno);
0430 void __iomem *pcsinst = spx5_inst_get(sparx5, pcs, tinst);
0431
0432
0433 spx5_inst_rmw(PCS10G_BR_PCS_CFG_PCS_ENA_SET(0),
0434 PCS10G_BR_PCS_CFG_PCS_ENA,
0435 pcsinst,
0436 PCS10G_BR_PCS_CFG(0));
0437
0438 if (sparx5_port_is_25g(port->portno))
0439
0440 spx5_rmw(DEV25G_PCS25G_CFG_PCS25G_ENA_SET(0),
0441 DEV25G_PCS25G_CFG_PCS25G_ENA,
0442 sparx5,
0443 DEV25G_PCS25G_CFG(tinst));
0444 } else {
0445
0446 spx5_rmw(DEV2G5_PCS1G_CFG_PCS_ENA_SET(0),
0447 DEV2G5_PCS1G_CFG_PCS_ENA,
0448 sparx5,
0449 DEV2G5_PCS1G_CFG(port->portno));
0450 }
0451
0452
0453 return 0;
0454 }
0455
0456 static int sparx5_port_fifo_sz(struct sparx5 *sparx5,
0457 u32 portno, u32 speed)
0458 {
0459 u32 sys_clk = sparx5_clk_period(sparx5->coreclock);
0460 const u32 taxi_dist[SPX5_PORTS_ALL] = {
0461 6, 8, 10, 6, 8, 10, 6, 8, 10, 6, 8, 10,
0462 4, 4, 4, 4,
0463 11, 12, 13, 14, 15, 16, 17, 18,
0464 11, 12, 13, 14, 15, 16, 17, 18,
0465 11, 12, 13, 14, 15, 16, 17, 18,
0466 11, 12, 13, 14, 15, 16, 17, 18,
0467 4, 6, 8, 4, 6, 8, 6, 8,
0468 2, 2, 2, 2, 2, 2, 2, 4, 2
0469 };
0470 u32 mac_per = 6400, tmp1, tmp2, tmp3;
0471 u32 fifo_width = 16;
0472 u32 mac_width = 8;
0473 u32 addition = 0;
0474
0475 switch (speed) {
0476 case SPEED_25000:
0477 return 0;
0478 case SPEED_10000:
0479 mac_per = 6400;
0480 mac_width = 8;
0481 addition = 1;
0482 break;
0483 case SPEED_5000:
0484 mac_per = 12800;
0485 mac_width = 8;
0486 addition = 0;
0487 break;
0488 case SPEED_2500:
0489 mac_per = 3200;
0490 mac_width = 1;
0491 addition = 0;
0492 break;
0493 case SPEED_1000:
0494 mac_per = 8000;
0495 mac_width = 1;
0496 addition = 0;
0497 break;
0498 case SPEED_100:
0499 case SPEED_10:
0500 return 1;
0501 default:
0502 break;
0503 }
0504
0505 tmp1 = 1000 * mac_width / fifo_width;
0506 tmp2 = 3000 + ((12000 + 2 * taxi_dist[portno] * 1000)
0507 * sys_clk / mac_per);
0508 tmp3 = tmp1 * tmp2 / 1000;
0509 return (tmp3 + 2000 + 999) / 1000 + addition;
0510 }
0511
0512
0513
0514
0515 static int sparx5_port_mux_set(struct sparx5 *sparx5,
0516 struct sparx5_port *port,
0517 struct sparx5_port_config *conf)
0518 {
0519 u32 portno = port->portno;
0520 u32 inst;
0521
0522 if (port->conf.portmode == conf->portmode)
0523 return 0;
0524
0525 switch (conf->portmode) {
0526 case PHY_INTERFACE_MODE_QSGMII:
0527 inst = (portno - portno % 4) / 4;
0528 spx5_rmw(BIT(inst),
0529 BIT(inst),
0530 sparx5,
0531 PORT_CONF_QSGMII_ENA);
0532
0533 if ((portno / 4 % 2) == 0) {
0534
0535 spx5_rmw(PORT_CONF_USGMII_CFG_BYPASS_SCRAM_SET(1) |
0536 PORT_CONF_USGMII_CFG_BYPASS_DESCRAM_SET(1) |
0537 PORT_CONF_USGMII_CFG_QUAD_MODE_SET(1),
0538 PORT_CONF_USGMII_CFG_BYPASS_SCRAM |
0539 PORT_CONF_USGMII_CFG_BYPASS_DESCRAM |
0540 PORT_CONF_USGMII_CFG_QUAD_MODE,
0541 sparx5,
0542 PORT_CONF_USGMII_CFG((portno / 8)));
0543 }
0544 break;
0545 default:
0546 break;
0547 }
0548 return 0;
0549 }
0550
0551 static int sparx5_port_max_tags_set(struct sparx5 *sparx5,
0552 struct sparx5_port *port)
0553 {
0554 enum sparx5_port_max_tags max_tags = port->max_vlan_tags;
0555 int tag_ct = max_tags == SPX5_PORT_MAX_TAGS_ONE ? 1 :
0556 max_tags == SPX5_PORT_MAX_TAGS_TWO ? 2 : 0;
0557 bool dtag = max_tags == SPX5_PORT_MAX_TAGS_TWO;
0558 enum sparx5_vlan_port_type vlan_type = port->vlan_type;
0559 bool dotag = max_tags != SPX5_PORT_MAX_TAGS_NONE;
0560 u32 dev = sparx5_to_high_dev(port->portno);
0561 u32 tinst = sparx5_port_dev_index(port->portno);
0562 void __iomem *inst = spx5_inst_get(sparx5, dev, tinst);
0563 u32 etype;
0564
0565 etype = (vlan_type == SPX5_VLAN_PORT_TYPE_S_CUSTOM ?
0566 port->custom_etype :
0567 vlan_type == SPX5_VLAN_PORT_TYPE_C ?
0568 SPX5_ETYPE_TAG_C : SPX5_ETYPE_TAG_S);
0569
0570 spx5_wr(DEV2G5_MAC_TAGS_CFG_TAG_ID_SET(etype) |
0571 DEV2G5_MAC_TAGS_CFG_PB_ENA_SET(dtag) |
0572 DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(dotag) |
0573 DEV2G5_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(dotag),
0574 sparx5,
0575 DEV2G5_MAC_TAGS_CFG(port->portno));
0576
0577 if (sparx5_port_is_2g5(port->portno))
0578 return 0;
0579
0580 spx5_inst_rmw(DEV10G_MAC_TAGS_CFG_TAG_ID_SET(etype) |
0581 DEV10G_MAC_TAGS_CFG_TAG_ENA_SET(dotag),
0582 DEV10G_MAC_TAGS_CFG_TAG_ID |
0583 DEV10G_MAC_TAGS_CFG_TAG_ENA,
0584 inst,
0585 DEV10G_MAC_TAGS_CFG(0, 0));
0586
0587 spx5_inst_rmw(DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS_SET(tag_ct),
0588 DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS,
0589 inst,
0590 DEV10G_MAC_NUM_TAGS_CFG(0));
0591
0592 spx5_inst_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(dotag),
0593 DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK,
0594 inst,
0595 DEV10G_MAC_MAXLEN_CFG(0));
0596 return 0;
0597 }
0598
0599 int sparx5_port_fwd_urg(struct sparx5 *sparx5, u32 speed)
0600 {
0601 u32 clk_period_ps = 1600;
0602 u32 urg = 672000;
0603
0604 switch (speed) {
0605 case SPEED_10:
0606 case SPEED_100:
0607 case SPEED_1000:
0608 urg = 672000;
0609 break;
0610 case SPEED_2500:
0611 urg = 270000;
0612 break;
0613 case SPEED_5000:
0614 urg = 135000;
0615 break;
0616 case SPEED_10000:
0617 urg = 67200;
0618 break;
0619 case SPEED_25000:
0620 urg = 27000;
0621 break;
0622 }
0623 return urg / clk_period_ps - 1;
0624 }
0625
0626 static u16 sparx5_wm_enc(u16 value)
0627 {
0628 if (value >= 2048)
0629 return 2048 + value / 16;
0630
0631 return value;
0632 }
0633
0634 static int sparx5_port_fc_setup(struct sparx5 *sparx5,
0635 struct sparx5_port *port,
0636 struct sparx5_port_config *conf)
0637 {
0638 bool fc_obey = conf->pause & MLO_PAUSE_RX ? 1 : 0;
0639 u32 pause_stop = 0xFFF - 1;
0640
0641 if (conf->pause & MLO_PAUSE_TX)
0642 pause_stop = sparx5_wm_enc(4 * (ETH_MAXLEN /
0643 SPX5_BUFFER_CELL_SZ));
0644
0645
0646 spx5_rmw(DSM_MAC_CFG_HDX_BACKPREASSURE_SET(conf->duplex == DUPLEX_HALF),
0647 DSM_MAC_CFG_HDX_BACKPREASSURE,
0648 sparx5,
0649 DSM_MAC_CFG(port->portno));
0650
0651
0652 spx5_rmw(DSM_RX_PAUSE_CFG_RX_PAUSE_EN_SET(fc_obey),
0653 DSM_RX_PAUSE_CFG_RX_PAUSE_EN,
0654 sparx5,
0655 DSM_RX_PAUSE_CFG(port->portno));
0656
0657
0658 spx5_rmw(QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS_SET(fc_obey),
0659 QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS,
0660 sparx5,
0661 QSYS_FWD_PRESSURE(port->portno));
0662
0663
0664 spx5_rmw(QSYS_PAUSE_CFG_PAUSE_STOP_SET(pause_stop),
0665 QSYS_PAUSE_CFG_PAUSE_STOP,
0666 sparx5,
0667 QSYS_PAUSE_CFG(port->portno));
0668
0669 return 0;
0670 }
0671
0672 static u16 sparx5_get_aneg_word(struct sparx5_port_config *conf)
0673 {
0674 if (conf->portmode == PHY_INTERFACE_MODE_1000BASEX)
0675 return (conf->pause_adv | ADVERTISE_LPACK | ADVERTISE_1000XFULL);
0676 else
0677 return 1;
0678 }
0679
0680 int sparx5_serdes_set(struct sparx5 *sparx5,
0681 struct sparx5_port *port,
0682 struct sparx5_port_config *conf)
0683 {
0684 int portmode, err, speed = conf->speed;
0685
0686 if (conf->portmode == PHY_INTERFACE_MODE_QSGMII &&
0687 ((port->portno % 4) != 0)) {
0688 return 0;
0689 }
0690 if (sparx5_is_baser(conf->portmode)) {
0691 if (conf->portmode == PHY_INTERFACE_MODE_25GBASER)
0692 speed = SPEED_25000;
0693 else if (conf->portmode == PHY_INTERFACE_MODE_10GBASER)
0694 speed = SPEED_10000;
0695 else
0696 speed = SPEED_5000;
0697 }
0698
0699 err = phy_set_media(port->serdes, conf->media);
0700 if (err)
0701 return err;
0702 if (speed > 0) {
0703 err = phy_set_speed(port->serdes, speed);
0704 if (err)
0705 return err;
0706 }
0707 if (conf->serdes_reset) {
0708 err = phy_reset(port->serdes);
0709 if (err)
0710 return err;
0711 }
0712
0713
0714
0715
0716 portmode = conf->portmode;
0717 if (sparx5_is_baser(conf->portmode))
0718 portmode = PHY_INTERFACE_MODE_10GBASER;
0719 err = phy_set_mode_ext(port->serdes, PHY_MODE_ETHERNET, portmode);
0720 if (err)
0721 return err;
0722 conf->serdes_reset = false;
0723 return err;
0724 }
0725
0726 static int sparx5_port_pcs_low_set(struct sparx5 *sparx5,
0727 struct sparx5_port *port,
0728 struct sparx5_port_config *conf)
0729 {
0730 bool sgmii = false, inband_aneg = false;
0731 int err;
0732
0733 if (port->conf.inband) {
0734 if (conf->portmode == PHY_INTERFACE_MODE_SGMII ||
0735 conf->portmode == PHY_INTERFACE_MODE_QSGMII)
0736 inband_aneg = true;
0737 else if (conf->portmode == PHY_INTERFACE_MODE_1000BASEX &&
0738 conf->autoneg)
0739 inband_aneg = true;
0740
0741 err = sparx5_serdes_set(sparx5, port, conf);
0742 if (err)
0743 return -EINVAL;
0744 } else {
0745 sgmii = true;
0746 }
0747
0748
0749 spx5_rmw(DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA_SET(sgmii),
0750 DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA,
0751 sparx5,
0752 DEV2G5_PCS1G_MODE_CFG(port->portno));
0753
0754
0755 spx5_wr(DEV2G5_PCS1G_CFG_PCS_ENA_SET(1),
0756 sparx5,
0757 DEV2G5_PCS1G_CFG(port->portno));
0758
0759 if (inband_aneg) {
0760 u16 abil = sparx5_get_aneg_word(conf);
0761
0762
0763 spx5_wr(DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY_SET(abil) |
0764 DEV2G5_PCS1G_ANEG_CFG_SW_RESOLVE_ENA_SET(1) |
0765 DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA_SET(1) |
0766 DEV2G5_PCS1G_ANEG_CFG_ANEG_RESTART_ONE_SHOT_SET(1),
0767 sparx5,
0768 DEV2G5_PCS1G_ANEG_CFG(port->portno));
0769 } else {
0770 spx5_wr(0, sparx5, DEV2G5_PCS1G_ANEG_CFG(port->portno));
0771 }
0772
0773
0774 spx5_rmw(DEV2G5_DEV_RST_CTRL_SPEED_SEL_SET(2) |
0775 DEV2G5_DEV_RST_CTRL_PCS_TX_RST_SET(0) |
0776 DEV2G5_DEV_RST_CTRL_PCS_RX_RST_SET(0),
0777 DEV2G5_DEV_RST_CTRL_SPEED_SEL |
0778 DEV2G5_DEV_RST_CTRL_PCS_TX_RST |
0779 DEV2G5_DEV_RST_CTRL_PCS_RX_RST,
0780 sparx5,
0781 DEV2G5_DEV_RST_CTRL(port->portno));
0782
0783 return 0;
0784 }
0785
0786 static int sparx5_port_pcs_high_set(struct sparx5 *sparx5,
0787 struct sparx5_port *port,
0788 struct sparx5_port_config *conf)
0789 {
0790 u32 clk_spd = conf->portmode == PHY_INTERFACE_MODE_5GBASER ? 1 : 0;
0791 u32 pix = sparx5_port_dev_index(port->portno);
0792 u32 dev = sparx5_to_high_dev(port->portno);
0793 u32 pcs = sparx5_to_pcs_dev(port->portno);
0794 void __iomem *devinst;
0795 void __iomem *pcsinst;
0796 int err;
0797
0798 devinst = spx5_inst_get(sparx5, dev, pix);
0799 pcsinst = spx5_inst_get(sparx5, pcs, pix);
0800
0801
0802 err = sparx5_serdes_set(sparx5, port, conf);
0803 if (err)
0804 return -EINVAL;
0805 if (conf->portmode == PHY_INTERFACE_MODE_25GBASER) {
0806
0807 spx5_rmw(DEV25G_PCS25G_CFG_PCS25G_ENA_SET(1),
0808 DEV25G_PCS25G_CFG_PCS25G_ENA,
0809 sparx5,
0810 DEV25G_PCS25G_CFG(pix));
0811 } else {
0812
0813 spx5_inst_rmw(PCS10G_BR_PCS_CFG_PCS_ENA_SET(1),
0814 PCS10G_BR_PCS_CFG_PCS_ENA,
0815 pcsinst,
0816 PCS10G_BR_PCS_CFG(0));
0817 }
0818
0819
0820 spx5_inst_wr(DEV10G_MAC_ENA_CFG_RX_ENA_SET(1) |
0821 DEV10G_MAC_ENA_CFG_TX_ENA_SET(1),
0822 devinst,
0823 DEV10G_MAC_ENA_CFG(0));
0824
0825
0826 spx5_inst_rmw(DEV10G_DEV_RST_CTRL_PCS_RX_RST_SET(0) |
0827 DEV10G_DEV_RST_CTRL_PCS_TX_RST_SET(0) |
0828 DEV10G_DEV_RST_CTRL_MAC_RX_RST_SET(0) |
0829 DEV10G_DEV_RST_CTRL_MAC_TX_RST_SET(0) |
0830 DEV10G_DEV_RST_CTRL_SPEED_SEL_SET(clk_spd),
0831 DEV10G_DEV_RST_CTRL_PCS_RX_RST |
0832 DEV10G_DEV_RST_CTRL_PCS_TX_RST |
0833 DEV10G_DEV_RST_CTRL_MAC_RX_RST |
0834 DEV10G_DEV_RST_CTRL_MAC_TX_RST |
0835 DEV10G_DEV_RST_CTRL_SPEED_SEL,
0836 devinst,
0837 DEV10G_DEV_RST_CTRL(0));
0838
0839 return 0;
0840 }
0841
0842
0843 static void sparx5_dev_switch(struct sparx5 *sparx5, int port, bool hsd)
0844 {
0845 int bt_indx = BIT(sparx5_port_dev_index(port));
0846
0847 if (sparx5_port_is_5g(port)) {
0848 spx5_rmw(hsd ? 0 : bt_indx,
0849 bt_indx,
0850 sparx5,
0851 PORT_CONF_DEV5G_MODES);
0852 } else if (sparx5_port_is_10g(port)) {
0853 spx5_rmw(hsd ? 0 : bt_indx,
0854 bt_indx,
0855 sparx5,
0856 PORT_CONF_DEV10G_MODES);
0857 } else if (sparx5_port_is_25g(port)) {
0858 spx5_rmw(hsd ? 0 : bt_indx,
0859 bt_indx,
0860 sparx5,
0861 PORT_CONF_DEV25G_MODES);
0862 }
0863 }
0864
0865
0866 static int sparx5_port_config_low_set(struct sparx5 *sparx5,
0867 struct sparx5_port *port,
0868 struct sparx5_port_config *conf)
0869 {
0870 u32 clk_spd, gig_mode, tx_gap, hdx_gap_1, hdx_gap_2;
0871 bool fdx = conf->duplex == DUPLEX_FULL;
0872 int spd = conf->speed;
0873
0874 clk_spd = spd == SPEED_10 ? 0 : spd == SPEED_100 ? 1 : 2;
0875 gig_mode = spd == SPEED_1000 || spd == SPEED_2500;
0876 tx_gap = spd == SPEED_1000 ? 4 : fdx ? 6 : 5;
0877 hdx_gap_1 = spd == SPEED_1000 ? 0 : spd == SPEED_100 ? 1 : 2;
0878 hdx_gap_2 = spd == SPEED_1000 ? 0 : spd == SPEED_100 ? 4 : 1;
0879
0880
0881 spx5_rmw(DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA_SET(gig_mode) |
0882 DEV2G5_MAC_MODE_CFG_FDX_ENA_SET(fdx),
0883 DEV2G5_MAC_MODE_CFG_GIGA_MODE_ENA |
0884 DEV2G5_MAC_MODE_CFG_FDX_ENA,
0885 sparx5,
0886 DEV2G5_MAC_MODE_CFG(port->portno));
0887
0888
0889 spx5_wr(DEV2G5_MAC_IFG_CFG_TX_IFG_SET(tx_gap) |
0890 DEV2G5_MAC_IFG_CFG_RX_IFG1_SET(hdx_gap_1) |
0891 DEV2G5_MAC_IFG_CFG_RX_IFG2_SET(hdx_gap_2),
0892 sparx5,
0893 DEV2G5_MAC_IFG_CFG(port->portno));
0894
0895
0896 spx5_rmw(HSCH_PORT_MODE_AGE_DIS_SET(fdx == 0),
0897 HSCH_PORT_MODE_AGE_DIS,
0898 sparx5,
0899 HSCH_PORT_MODE(port->portno));
0900
0901
0902 spx5_wr(DEV2G5_MAC_ENA_CFG_RX_ENA |
0903 DEV2G5_MAC_ENA_CFG_TX_ENA,
0904 sparx5,
0905 DEV2G5_MAC_ENA_CFG(port->portno));
0906
0907
0908 spx5_rmw(DEV2G5_DEV_RST_CTRL_SPEED_SEL_SET(clk_spd) |
0909 DEV2G5_DEV_RST_CTRL_MAC_TX_RST_SET(0) |
0910 DEV2G5_DEV_RST_CTRL_MAC_RX_RST_SET(0),
0911 DEV2G5_DEV_RST_CTRL_SPEED_SEL |
0912 DEV2G5_DEV_RST_CTRL_MAC_TX_RST |
0913 DEV2G5_DEV_RST_CTRL_MAC_RX_RST,
0914 sparx5,
0915 DEV2G5_DEV_RST_CTRL(port->portno));
0916
0917 return 0;
0918 }
0919
0920 int sparx5_port_pcs_set(struct sparx5 *sparx5,
0921 struct sparx5_port *port,
0922 struct sparx5_port_config *conf)
0923
0924 {
0925 bool high_speed_dev = sparx5_is_baser(conf->portmode);
0926 int err;
0927
0928 if (sparx5_dev_change(sparx5, port, conf)) {
0929
0930 sparx5_dev_switch(sparx5, port->portno, high_speed_dev);
0931
0932
0933 err = sparx5_port_disable(sparx5, port, !high_speed_dev);
0934 if (err)
0935 return err;
0936 }
0937
0938 err = sparx5_port_disable(sparx5, port, high_speed_dev);
0939 if (err)
0940 return -EINVAL;
0941
0942 if (high_speed_dev)
0943 err = sparx5_port_pcs_high_set(sparx5, port, conf);
0944 else
0945 err = sparx5_port_pcs_low_set(sparx5, port, conf);
0946
0947 if (err)
0948 return -EINVAL;
0949
0950 if (port->conf.inband) {
0951
0952 spx5_rmw(ASM_PORT_CFG_CSC_STAT_DIS_SET(high_speed_dev),
0953 ASM_PORT_CFG_CSC_STAT_DIS,
0954 sparx5,
0955 ASM_PORT_CFG(port->portno));
0956
0957
0958 spx5_rmw(DSM_BUF_CFG_CSC_STAT_DIS_SET(high_speed_dev),
0959 DSM_BUF_CFG_CSC_STAT_DIS,
0960 sparx5,
0961 DSM_BUF_CFG(port->portno));
0962 }
0963
0964 port->conf = *conf;
0965
0966 return 0;
0967 }
0968
0969 int sparx5_port_config(struct sparx5 *sparx5,
0970 struct sparx5_port *port,
0971 struct sparx5_port_config *conf)
0972 {
0973 bool high_speed_dev = sparx5_is_baser(conf->portmode);
0974 int err, urgency, stop_wm;
0975
0976 err = sparx5_port_verify_speed(sparx5, port, conf);
0977 if (err)
0978 return err;
0979
0980
0981 if (!high_speed_dev)
0982 sparx5_port_config_low_set(sparx5, port, conf);
0983
0984
0985 err = sparx5_port_fc_setup(sparx5, port, conf);
0986 if (err)
0987 return err;
0988
0989
0990 stop_wm = sparx5_port_fifo_sz(sparx5, port->portno, conf->speed);
0991 spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_SET(stop_wm),
0992 DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM,
0993 sparx5,
0994 DSM_DEV_TX_STOP_WM_CFG(port->portno));
0995
0996
0997 urgency = sparx5_port_fwd_urg(sparx5, conf->speed);
0998 spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(1) |
0999 QFWD_SWITCH_PORT_MODE_FWD_URGENCY_SET(urgency),
1000 QFWD_SWITCH_PORT_MODE_PORT_ENA |
1001 QFWD_SWITCH_PORT_MODE_FWD_URGENCY,
1002 sparx5,
1003 QFWD_SWITCH_PORT_MODE(port->portno));
1004
1005
1006 port->conf = *conf;
1007
1008 return 0;
1009 }
1010
1011
1012 int sparx5_port_init(struct sparx5 *sparx5,
1013 struct sparx5_port *port,
1014 struct sparx5_port_config *conf)
1015 {
1016 u32 pause_start = sparx5_wm_enc(6 * (ETH_MAXLEN / SPX5_BUFFER_CELL_SZ));
1017 u32 atop = sparx5_wm_enc(20 * (ETH_MAXLEN / SPX5_BUFFER_CELL_SZ));
1018 u32 devhigh = sparx5_to_high_dev(port->portno);
1019 u32 pix = sparx5_port_dev_index(port->portno);
1020 u32 pcs = sparx5_to_pcs_dev(port->portno);
1021 bool sd_pol = port->signd_active_high;
1022 bool sd_sel = !port->signd_internal;
1023 bool sd_ena = port->signd_enable;
1024 u32 pause_stop = 0xFFF - 1;
1025 void __iomem *devinst;
1026 void __iomem *pcsinst;
1027 int err;
1028
1029 devinst = spx5_inst_get(sparx5, devhigh, pix);
1030 pcsinst = spx5_inst_get(sparx5, pcs, pix);
1031
1032
1033 err = sparx5_port_mux_set(sparx5, port, conf);
1034 if (err)
1035 return err;
1036
1037
1038 err = sparx5_port_max_tags_set(sparx5, port);
1039 if (err)
1040 return err;
1041
1042
1043 spx5_rmw(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN),
1044 DEV2G5_MAC_MAXLEN_CFG_MAX_LEN,
1045 sparx5,
1046 DEV2G5_MAC_MAXLEN_CFG(port->portno));
1047
1048
1049 spx5_wr(DEV2G5_PCS1G_SD_CFG_SD_POL_SET(sd_pol) |
1050 DEV2G5_PCS1G_SD_CFG_SD_SEL_SET(sd_sel) |
1051 DEV2G5_PCS1G_SD_CFG_SD_ENA_SET(sd_ena),
1052 sparx5,
1053 DEV2G5_PCS1G_SD_CFG(port->portno));
1054
1055
1056 spx5_rmw(QSYS_PAUSE_CFG_PAUSE_START_SET(pause_start) |
1057 QSYS_PAUSE_CFG_PAUSE_STOP_SET(pause_stop) |
1058 QSYS_PAUSE_CFG_PAUSE_ENA_SET(1),
1059 QSYS_PAUSE_CFG_PAUSE_START |
1060 QSYS_PAUSE_CFG_PAUSE_STOP |
1061 QSYS_PAUSE_CFG_PAUSE_ENA,
1062 sparx5,
1063 QSYS_PAUSE_CFG(port->portno));
1064
1065
1066 spx5_wr(QSYS_ATOP_ATOP_SET(atop),
1067 sparx5,
1068 QSYS_ATOP(port->portno));
1069
1070
1071 spx5_wr(PAUSE_DISCARD, sparx5, ANA_CL_CAPTURE_BPDU_CFG(port->portno));
1072
1073 if (conf->portmode == PHY_INTERFACE_MODE_QSGMII ||
1074 conf->portmode == PHY_INTERFACE_MODE_SGMII) {
1075 err = sparx5_serdes_set(sparx5, port, conf);
1076 if (err)
1077 return err;
1078
1079 if (!sparx5_port_is_2g5(port->portno))
1080
1081 spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA_SET(1),
1082 DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA,
1083 sparx5,
1084 DSM_DEV_TX_STOP_WM_CFG(port->portno));
1085
1086 sparx5_dev_switch(sparx5, port->portno, false);
1087 }
1088 if (conf->portmode == PHY_INTERFACE_MODE_QSGMII) {
1089
1090 spx5_rmw(DEV2G5_DEV_RST_CTRL_PCS_TX_RST_SET(0),
1091 DEV2G5_DEV_RST_CTRL_PCS_TX_RST,
1092 sparx5,
1093 DEV2G5_DEV_RST_CTRL(port->portno));
1094 }
1095
1096 spx5_wr(DEV2G5_MAC_IFG_CFG_TX_IFG_SET(6) |
1097 DEV2G5_MAC_IFG_CFG_RX_IFG1_SET(0) |
1098 DEV2G5_MAC_IFG_CFG_RX_IFG2_SET(0),
1099 sparx5,
1100 DEV2G5_MAC_IFG_CFG(port->portno));
1101
1102 if (sparx5_port_is_2g5(port->portno))
1103 return 0;
1104
1105
1106 if (conf->portmode == PHY_INTERFACE_MODE_NA)
1107 conf->portmode = PHY_INTERFACE_MODE_10GBASER;
1108
1109 if (sparx5_is_baser(conf->portmode))
1110 sparx5_dev_switch(sparx5, port->portno, true);
1111
1112
1113 spx5_inst_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN),
1114 DEV10G_MAC_MAXLEN_CFG_MAX_LEN,
1115 devinst,
1116 DEV10G_MAC_ENA_CFG(0));
1117
1118
1119 spx5_inst_wr(PCS10G_BR_PCS_SD_CFG_SD_POL_SET(sd_pol) |
1120 PCS10G_BR_PCS_SD_CFG_SD_SEL_SET(sd_sel) |
1121 PCS10G_BR_PCS_SD_CFG_SD_ENA_SET(sd_ena),
1122 pcsinst,
1123 PCS10G_BR_PCS_SD_CFG(0));
1124
1125 if (sparx5_port_is_25g(port->portno)) {
1126
1127 spx5_wr(DEV25G_PCS25G_SD_CFG_SD_POL_SET(sd_pol) |
1128 DEV25G_PCS25G_SD_CFG_SD_SEL_SET(sd_sel) |
1129 DEV25G_PCS25G_SD_CFG_SD_ENA_SET(sd_ena),
1130 sparx5,
1131 DEV25G_PCS25G_SD_CFG(pix));
1132 }
1133
1134 return 0;
1135 }
1136
1137 void sparx5_port_enable(struct sparx5_port *port, bool enable)
1138 {
1139 struct sparx5 *sparx5 = port->sparx5;
1140
1141
1142 spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(enable),
1143 QFWD_SWITCH_PORT_MODE_PORT_ENA,
1144 sparx5,
1145 QFWD_SWITCH_PORT_MODE(port->portno));
1146 }