852 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2020 NovaTech LLC4 * George McCollister <george.mccollister@gmail.com>5 */6 7#include <net/dsa.h>8#include <linux/etherdevice.h>9#include <linux/if_bridge.h>10#include <linux/of.h>11#include <linux/netdev_features.h>12#include <linux/if_hsr.h>13#include "xrs700x.h"14#include "xrs700x_reg.h"15 16#define XRS700X_MIB_INTERVAL msecs_to_jiffies(3000)17 18#define XRS7000X_SUPPORTED_HSR_FEATURES \19 (NETIF_F_HW_HSR_TAG_INS | NETIF_F_HW_HSR_TAG_RM | \20 NETIF_F_HW_HSR_FWD | NETIF_F_HW_HSR_DUP)21 22#define XRS7003E_ID 0x10023#define XRS7003F_ID 0x10124#define XRS7004E_ID 0x20025#define XRS7004F_ID 0x20126 27const struct xrs700x_info xrs7003e_info = {XRS7003E_ID, "XRS7003E", 3};28EXPORT_SYMBOL(xrs7003e_info);29 30const struct xrs700x_info xrs7003f_info = {XRS7003F_ID, "XRS7003F", 3};31EXPORT_SYMBOL(xrs7003f_info);32 33const struct xrs700x_info xrs7004e_info = {XRS7004E_ID, "XRS7004E", 4};34EXPORT_SYMBOL(xrs7004e_info);35 36const struct xrs700x_info xrs7004f_info = {XRS7004F_ID, "XRS7004F", 4};37EXPORT_SYMBOL(xrs7004f_info);38 39struct xrs700x_regfield {40 struct reg_field rf;41 struct regmap_field **rmf;42};43 44struct xrs700x_mib {45 unsigned int offset;46 const char *name;47 int stats64_offset;48};49 50#define XRS700X_MIB_ETHTOOL_ONLY(o, n) {o, n, -1}51#define XRS700X_MIB(o, n, m) {o, n, offsetof(struct rtnl_link_stats64, m)}52 53static const struct xrs700x_mib xrs700x_mibs[] = {54 XRS700X_MIB(XRS_RX_GOOD_OCTETS_L, "rx_good_octets", rx_bytes),55 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_BAD_OCTETS_L, "rx_bad_octets"),56 XRS700X_MIB(XRS_RX_UNICAST_L, "rx_unicast", rx_packets),57 XRS700X_MIB(XRS_RX_BROADCAST_L, "rx_broadcast", rx_packets),58 XRS700X_MIB(XRS_RX_MULTICAST_L, "rx_multicast", multicast),59 XRS700X_MIB(XRS_RX_UNDERSIZE_L, "rx_undersize", rx_length_errors),60 XRS700X_MIB(XRS_RX_FRAGMENTS_L, "rx_fragments", rx_length_errors),61 XRS700X_MIB(XRS_RX_OVERSIZE_L, "rx_oversize", rx_length_errors),62 XRS700X_MIB(XRS_RX_JABBER_L, "rx_jabber", rx_length_errors),63 XRS700X_MIB(XRS_RX_ERR_L, "rx_err", rx_errors),64 XRS700X_MIB(XRS_RX_CRC_L, "rx_crc", rx_crc_errors),65 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_64_L, "rx_64"),66 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_65_127_L, "rx_65_127"),67 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_128_255_L, "rx_128_255"),68 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_256_511_L, "rx_256_511"),69 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_512_1023_L, "rx_512_1023"),70 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_1024_1536_L, "rx_1024_1536"),71 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_HSR_PRP_L, "rx_hsr_prp"),72 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_WRONGLAN_L, "rx_wronglan"),73 XRS700X_MIB_ETHTOOL_ONLY(XRS_RX_DUPLICATE_L, "rx_duplicate"),74 XRS700X_MIB(XRS_TX_OCTETS_L, "tx_octets", tx_bytes),75 XRS700X_MIB(XRS_TX_UNICAST_L, "tx_unicast", tx_packets),76 XRS700X_MIB(XRS_TX_BROADCAST_L, "tx_broadcast", tx_packets),77 XRS700X_MIB(XRS_TX_MULTICAST_L, "tx_multicast", tx_packets),78 XRS700X_MIB_ETHTOOL_ONLY(XRS_TX_HSR_PRP_L, "tx_hsr_prp"),79 XRS700X_MIB(XRS_PRIQ_DROP_L, "priq_drop", tx_dropped),80 XRS700X_MIB(XRS_EARLY_DROP_L, "early_drop", tx_dropped),81};82 83static const u8 eth_hsrsup_addr[ETH_ALEN] = {84 0x01, 0x15, 0x4e, 0x00, 0x01, 0x00};85 86static void xrs700x_get_strings(struct dsa_switch *ds, int port,87 u32 stringset, u8 *data)88{89 int i;90 91 if (stringset != ETH_SS_STATS)92 return;93 94 for (i = 0; i < ARRAY_SIZE(xrs700x_mibs); i++) {95 strscpy(data, xrs700x_mibs[i].name, ETH_GSTRING_LEN);96 data += ETH_GSTRING_LEN;97 }98}99 100static int xrs700x_get_sset_count(struct dsa_switch *ds, int port, int sset)101{102 if (sset != ETH_SS_STATS)103 return -EOPNOTSUPP;104 105 return ARRAY_SIZE(xrs700x_mibs);106}107 108static void xrs700x_read_port_counters(struct xrs700x *priv, int port)109{110 struct xrs700x_port *p = &priv->ports[port];111 struct rtnl_link_stats64 stats;112 unsigned long flags;113 int i;114 115 memset(&stats, 0, sizeof(stats));116 117 mutex_lock(&p->mib_mutex);118 119 /* Capture counter values */120 regmap_write(priv->regmap, XRS_CNT_CTRL(port), 1);121 122 for (i = 0; i < ARRAY_SIZE(xrs700x_mibs); i++) {123 unsigned int high = 0, low = 0, reg;124 125 reg = xrs700x_mibs[i].offset + XRS_PORT_OFFSET * port;126 regmap_read(priv->regmap, reg, &low);127 regmap_read(priv->regmap, reg + 2, &high);128 129 p->mib_data[i] += (high << 16) | low;130 131 if (xrs700x_mibs[i].stats64_offset >= 0) {132 u8 *s = (u8 *)&stats + xrs700x_mibs[i].stats64_offset;133 *(u64 *)s += p->mib_data[i];134 }135 }136 137 /* multicast must be added to rx_packets (which already includes138 * unicast and broadcast)139 */140 stats.rx_packets += stats.multicast;141 142 flags = u64_stats_update_begin_irqsave(&p->syncp);143 p->stats64 = stats;144 u64_stats_update_end_irqrestore(&p->syncp, flags);145 146 mutex_unlock(&p->mib_mutex);147}148 149static void xrs700x_mib_work(struct work_struct *work)150{151 struct xrs700x *priv = container_of(work, struct xrs700x,152 mib_work.work);153 int i;154 155 for (i = 0; i < priv->ds->num_ports; i++)156 xrs700x_read_port_counters(priv, i);157 158 schedule_delayed_work(&priv->mib_work, XRS700X_MIB_INTERVAL);159}160 161static void xrs700x_get_ethtool_stats(struct dsa_switch *ds, int port,162 u64 *data)163{164 struct xrs700x *priv = ds->priv;165 struct xrs700x_port *p = &priv->ports[port];166 167 xrs700x_read_port_counters(priv, port);168 169 mutex_lock(&p->mib_mutex);170 memcpy(data, p->mib_data, sizeof(*data) * ARRAY_SIZE(xrs700x_mibs));171 mutex_unlock(&p->mib_mutex);172}173 174static void xrs700x_get_stats64(struct dsa_switch *ds, int port,175 struct rtnl_link_stats64 *s)176{177 struct xrs700x *priv = ds->priv;178 struct xrs700x_port *p = &priv->ports[port];179 unsigned int start;180 181 do {182 start = u64_stats_fetch_begin(&p->syncp);183 *s = p->stats64;184 } while (u64_stats_fetch_retry(&p->syncp, start));185}186 187static int xrs700x_setup_regmap_range(struct xrs700x *priv)188{189 struct xrs700x_regfield regfields[] = {190 {191 .rf = REG_FIELD_ID(XRS_PORT_STATE(0), 0, 1,192 priv->ds->num_ports,193 XRS_PORT_OFFSET),194 .rmf = &priv->ps_forward195 },196 {197 .rf = REG_FIELD_ID(XRS_PORT_STATE(0), 2, 3,198 priv->ds->num_ports,199 XRS_PORT_OFFSET),200 .rmf = &priv->ps_management201 },202 {203 .rf = REG_FIELD_ID(XRS_PORT_STATE(0), 4, 9,204 priv->ds->num_ports,205 XRS_PORT_OFFSET),206 .rmf = &priv->ps_sel_speed207 },208 {209 .rf = REG_FIELD_ID(XRS_PORT_STATE(0), 10, 11,210 priv->ds->num_ports,211 XRS_PORT_OFFSET),212 .rmf = &priv->ps_cur_speed213 }214 };215 int i = 0;216 217 for (; i < ARRAY_SIZE(regfields); i++) {218 *regfields[i].rmf = devm_regmap_field_alloc(priv->dev,219 priv->regmap,220 regfields[i].rf);221 if (IS_ERR(*regfields[i].rmf))222 return PTR_ERR(*regfields[i].rmf);223 }224 225 return 0;226}227 228static enum dsa_tag_protocol xrs700x_get_tag_protocol(struct dsa_switch *ds,229 int port,230 enum dsa_tag_protocol m)231{232 return DSA_TAG_PROTO_XRS700X;233}234 235static int xrs700x_reset(struct dsa_switch *ds)236{237 struct xrs700x *priv = ds->priv;238 unsigned int val;239 int ret;240 241 ret = regmap_write(priv->regmap, XRS_GENERAL, XRS_GENERAL_RESET);242 if (ret)243 goto error;244 245 ret = regmap_read_poll_timeout(priv->regmap, XRS_GENERAL,246 val, !(val & XRS_GENERAL_RESET),247 10, 1000);248error:249 if (ret) {250 dev_err_ratelimited(priv->dev, "error resetting switch: %d\n",251 ret);252 }253 254 return ret;255}256 257static void xrs700x_port_stp_state_set(struct dsa_switch *ds, int port,258 u8 state)259{260 struct xrs700x *priv = ds->priv;261 unsigned int bpdus = 1;262 unsigned int val;263 264 switch (state) {265 case BR_STATE_DISABLED:266 bpdus = 0;267 fallthrough;268 case BR_STATE_BLOCKING:269 case BR_STATE_LISTENING:270 val = XRS_PORT_DISABLED;271 break;272 case BR_STATE_LEARNING:273 val = XRS_PORT_LEARNING;274 break;275 case BR_STATE_FORWARDING:276 val = XRS_PORT_FORWARDING;277 break;278 default:279 dev_err(ds->dev, "invalid STP state: %d\n", state);280 return;281 }282 283 regmap_fields_write(priv->ps_forward, port, val);284 285 /* Enable/disable inbound policy added by xrs700x_port_add_bpdu_ipf()286 * which allows BPDU forwarding to the CPU port when the front facing287 * port is in disabled/learning state.288 */289 regmap_update_bits(priv->regmap, XRS_ETH_ADDR_CFG(port, 0), 1, bpdus);290 291 dev_dbg_ratelimited(priv->dev, "%s - port: %d, state: %u, val: 0x%x\n",292 __func__, port, state, val);293}294 295/* Add an inbound policy filter which matches the BPDU destination MAC296 * and forwards to the CPU port. Leave the policy disabled, it will be297 * enabled as needed.298 */299static int xrs700x_port_add_bpdu_ipf(struct dsa_switch *ds, int port)300{301 struct xrs700x *priv = ds->priv;302 unsigned int val = 0;303 int i = 0;304 int ret;305 306 /* Compare all 48 bits of the destination MAC address. */307 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_CFG(port, 0), 48 << 2);308 if (ret)309 return ret;310 311 /* match BPDU destination 01:80:c2:00:00:00 */312 for (i = 0; i < sizeof(eth_stp_addr); i += 2) {313 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_0(port, 0) + i,314 eth_stp_addr[i] |315 (eth_stp_addr[i + 1] << 8));316 if (ret)317 return ret;318 }319 320 /* Mirror BPDU to CPU port */321 for (i = 0; i < ds->num_ports; i++) {322 if (dsa_is_cpu_port(ds, i))323 val |= BIT(i);324 }325 326 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_FWD_MIRROR(port, 0), val);327 if (ret)328 return ret;329 330 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_FWD_ALLOW(port, 0), 0);331 if (ret)332 return ret;333 334 return 0;335}336 337/* Add an inbound policy filter which matches the HSR/PRP supervision MAC338 * range and forwards to the CPU port without discarding duplicates.339 * This is required to correctly populate the HSR/PRP node_table.340 * Leave the policy disabled, it will be enabled as needed.341 */342static int xrs700x_port_add_hsrsup_ipf(struct dsa_switch *ds, int port,343 int fwdport)344{345 struct xrs700x *priv = ds->priv;346 unsigned int val = 0;347 int i = 0;348 int ret;349 350 /* Compare 40 bits of the destination MAC address. */351 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_CFG(port, 1), 40 << 2);352 if (ret)353 return ret;354 355 /* match HSR/PRP supervision destination 01:15:4e:00:01:XX */356 for (i = 0; i < sizeof(eth_hsrsup_addr); i += 2) {357 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_0(port, 1) + i,358 eth_hsrsup_addr[i] |359 (eth_hsrsup_addr[i + 1] << 8));360 if (ret)361 return ret;362 }363 364 /* Mirror HSR/PRP supervision to CPU port */365 for (i = 0; i < ds->num_ports; i++) {366 if (dsa_is_cpu_port(ds, i))367 val |= BIT(i);368 }369 370 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_FWD_MIRROR(port, 1), val);371 if (ret)372 return ret;373 374 if (fwdport >= 0)375 val |= BIT(fwdport);376 377 /* Allow must be set prevent duplicate discard */378 ret = regmap_write(priv->regmap, XRS_ETH_ADDR_FWD_ALLOW(port, 1), val);379 if (ret)380 return ret;381 382 return 0;383}384 385static int xrs700x_port_setup(struct dsa_switch *ds, int port)386{387 bool cpu_port = dsa_is_cpu_port(ds, port);388 struct xrs700x *priv = ds->priv;389 unsigned int val = 0;390 int ret, i;391 392 xrs700x_port_stp_state_set(ds, port, BR_STATE_DISABLED);393 394 /* Disable forwarding to non-CPU ports */395 for (i = 0; i < ds->num_ports; i++) {396 if (!dsa_is_cpu_port(ds, i))397 val |= BIT(i);398 }399 400 /* 1 = Disable forwarding to the port */401 ret = regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port), val);402 if (ret)403 return ret;404 405 val = cpu_port ? XRS_PORT_MODE_MANAGEMENT : XRS_PORT_MODE_NORMAL;406 ret = regmap_fields_write(priv->ps_management, port, val);407 if (ret)408 return ret;409 410 if (!cpu_port) {411 ret = xrs700x_port_add_bpdu_ipf(ds, port);412 if (ret)413 return ret;414 }415 416 return 0;417}418 419static int xrs700x_setup(struct dsa_switch *ds)420{421 struct xrs700x *priv = ds->priv;422 int ret, i;423 424 ret = xrs700x_reset(ds);425 if (ret)426 return ret;427 428 for (i = 0; i < ds->num_ports; i++) {429 ret = xrs700x_port_setup(ds, i);430 if (ret)431 return ret;432 }433 434 schedule_delayed_work(&priv->mib_work, XRS700X_MIB_INTERVAL);435 436 return 0;437}438 439static void xrs700x_teardown(struct dsa_switch *ds)440{441 struct xrs700x *priv = ds->priv;442 443 cancel_delayed_work_sync(&priv->mib_work);444}445 446static void xrs700x_phylink_get_caps(struct dsa_switch *ds, int port,447 struct phylink_config *config)448{449 switch (port) {450 case 0:451 __set_bit(PHY_INTERFACE_MODE_RMII,452 config->supported_interfaces);453 config->mac_capabilities = MAC_10FD | MAC_100FD;454 break;455 456 case 1:457 case 2:458 case 3:459 phy_interface_set_rgmii(config->supported_interfaces);460 config->mac_capabilities = MAC_10FD | MAC_100FD | MAC_1000FD;461 break;462 463 default:464 dev_err(ds->dev, "Unsupported port: %i\n", port);465 break;466 }467}468 469static void xrs700x_mac_config(struct phylink_config *config, unsigned int mode,470 const struct phylink_link_state *state)471{472}473 474static void xrs700x_mac_link_down(struct phylink_config *config,475 unsigned int mode, phy_interface_t interface)476{477}478 479static void xrs700x_mac_link_up(struct phylink_config *config,480 struct phy_device *phydev,481 unsigned int mode, phy_interface_t interface,482 int speed, int duplex,483 bool tx_pause, bool rx_pause)484{485 struct dsa_port *dp = dsa_phylink_to_port(config);486 struct xrs700x *priv = dp->ds->priv;487 int port = dp->index;488 unsigned int val;489 490 switch (speed) {491 case SPEED_1000:492 val = XRS_PORT_SPEED_1000;493 break;494 case SPEED_100:495 val = XRS_PORT_SPEED_100;496 break;497 case SPEED_10:498 val = XRS_PORT_SPEED_10;499 break;500 default:501 return;502 }503 504 regmap_fields_write(priv->ps_sel_speed, port, val);505 506 dev_dbg_ratelimited(priv->dev, "%s: port: %d mode: %u speed: %u\n",507 __func__, port, mode, speed);508}509 510static int xrs700x_bridge_common(struct dsa_switch *ds, int port,511 struct dsa_bridge bridge, bool join)512{513 unsigned int i, cpu_mask = 0, mask = 0;514 struct xrs700x *priv = ds->priv;515 int ret;516 517 for (i = 0; i < ds->num_ports; i++) {518 if (dsa_is_cpu_port(ds, i))519 continue;520 521 cpu_mask |= BIT(i);522 523 if (dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))524 continue;525 526 mask |= BIT(i);527 }528 529 for (i = 0; i < ds->num_ports; i++) {530 if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))531 continue;532 533 /* 1 = Disable forwarding to the port */534 ret = regmap_write(priv->regmap, XRS_PORT_FWD_MASK(i), mask);535 if (ret)536 return ret;537 }538 539 if (!join) {540 ret = regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port),541 cpu_mask);542 if (ret)543 return ret;544 }545 546 return 0;547}548 549static int xrs700x_bridge_join(struct dsa_switch *ds, int port,550 struct dsa_bridge bridge, bool *tx_fwd_offload,551 struct netlink_ext_ack *extack)552{553 return xrs700x_bridge_common(ds, port, bridge, true);554}555 556static void xrs700x_bridge_leave(struct dsa_switch *ds, int port,557 struct dsa_bridge bridge)558{559 xrs700x_bridge_common(ds, port, bridge, false);560}561 562static int xrs700x_hsr_join(struct dsa_switch *ds, int port,563 struct net_device *hsr,564 struct netlink_ext_ack *extack)565{566 unsigned int val = XRS_HSR_CFG_HSR_PRP;567 struct dsa_port *partner = NULL, *dp;568 struct xrs700x *priv = ds->priv;569 struct net_device *user;570 int ret, i, hsr_pair[2];571 enum hsr_version ver;572 bool fwd = false;573 574 ret = hsr_get_version(hsr, &ver);575 if (ret)576 return ret;577 578 if (port != 1 && port != 2) {579 NL_SET_ERR_MSG_MOD(extack,580 "Only ports 1 and 2 can offload HSR/PRP");581 return -EOPNOTSUPP;582 }583 584 if (ver == HSR_V1) {585 val |= XRS_HSR_CFG_HSR;586 } else if (ver == PRP_V1) {587 val |= XRS_HSR_CFG_PRP;588 } else {589 NL_SET_ERR_MSG_MOD(extack,590 "Only HSR v1 and PRP v1 can be offloaded");591 return -EOPNOTSUPP;592 }593 594 dsa_hsr_foreach_port(dp, ds, hsr) {595 if (dp->index != port) {596 partner = dp;597 break;598 }599 }600 601 /* We can't enable redundancy on the switch until both602 * redundant ports have signed up.603 */604 if (!partner)605 return 0;606 607 regmap_fields_write(priv->ps_forward, partner->index,608 XRS_PORT_DISABLED);609 regmap_fields_write(priv->ps_forward, port, XRS_PORT_DISABLED);610 611 regmap_write(priv->regmap, XRS_HSR_CFG(partner->index),612 val | XRS_HSR_CFG_LANID_A);613 regmap_write(priv->regmap, XRS_HSR_CFG(port),614 val | XRS_HSR_CFG_LANID_B);615 616 /* Clear bits for both redundant ports (HSR only) and the CPU port to617 * enable forwarding.618 */619 val = GENMASK(ds->num_ports - 1, 0);620 if (ver == HSR_V1) {621 val &= ~BIT(partner->index);622 val &= ~BIT(port);623 fwd = true;624 }625 val &= ~BIT(dsa_upstream_port(ds, port));626 regmap_write(priv->regmap, XRS_PORT_FWD_MASK(partner->index), val);627 regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port), val);628 629 regmap_fields_write(priv->ps_forward, partner->index,630 XRS_PORT_FORWARDING);631 regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING);632 633 /* Enable inbound policy which allows HSR/PRP supervision forwarding634 * to the CPU port without discarding duplicates. Continue to635 * forward to redundant ports when in HSR mode while discarding636 * duplicates.637 */638 ret = xrs700x_port_add_hsrsup_ipf(ds, partner->index, fwd ? port : -1);639 if (ret)640 return ret;641 642 ret = xrs700x_port_add_hsrsup_ipf(ds, port, fwd ? partner->index : -1);643 if (ret)644 return ret;645 646 regmap_update_bits(priv->regmap,647 XRS_ETH_ADDR_CFG(partner->index, 1), 1, 1);648 regmap_update_bits(priv->regmap, XRS_ETH_ADDR_CFG(port, 1), 1, 1);649 650 hsr_pair[0] = port;651 hsr_pair[1] = partner->index;652 for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) {653 user = dsa_to_port(ds, hsr_pair[i])->user;654 user->features |= XRS7000X_SUPPORTED_HSR_FEATURES;655 }656 657 return 0;658}659 660static int xrs700x_hsr_leave(struct dsa_switch *ds, int port,661 struct net_device *hsr)662{663 struct dsa_port *partner = NULL, *dp;664 struct xrs700x *priv = ds->priv;665 struct net_device *user;666 int i, hsr_pair[2];667 unsigned int val;668 669 dsa_hsr_foreach_port(dp, ds, hsr) {670 if (dp->index != port) {671 partner = dp;672 break;673 }674 }675 676 if (!partner)677 return 0;678 679 regmap_fields_write(priv->ps_forward, partner->index,680 XRS_PORT_DISABLED);681 regmap_fields_write(priv->ps_forward, port, XRS_PORT_DISABLED);682 683 regmap_write(priv->regmap, XRS_HSR_CFG(partner->index), 0);684 regmap_write(priv->regmap, XRS_HSR_CFG(port), 0);685 686 /* Clear bit for the CPU port to enable forwarding. */687 val = GENMASK(ds->num_ports - 1, 0);688 val &= ~BIT(dsa_upstream_port(ds, port));689 regmap_write(priv->regmap, XRS_PORT_FWD_MASK(partner->index), val);690 regmap_write(priv->regmap, XRS_PORT_FWD_MASK(port), val);691 692 regmap_fields_write(priv->ps_forward, partner->index,693 XRS_PORT_FORWARDING);694 regmap_fields_write(priv->ps_forward, port, XRS_PORT_FORWARDING);695 696 /* Disable inbound policy added by xrs700x_port_add_hsrsup_ipf()697 * which allows HSR/PRP supervision forwarding to the CPU port without698 * discarding duplicates.699 */700 regmap_update_bits(priv->regmap,701 XRS_ETH_ADDR_CFG(partner->index, 1), 1, 0);702 regmap_update_bits(priv->regmap, XRS_ETH_ADDR_CFG(port, 1), 1, 0);703 704 hsr_pair[0] = port;705 hsr_pair[1] = partner->index;706 for (i = 0; i < ARRAY_SIZE(hsr_pair); i++) {707 user = dsa_to_port(ds, hsr_pair[i])->user;708 user->features &= ~XRS7000X_SUPPORTED_HSR_FEATURES;709 }710 711 return 0;712}713 714static const struct phylink_mac_ops xrs700x_phylink_mac_ops = {715 .mac_config = xrs700x_mac_config,716 .mac_link_down = xrs700x_mac_link_down,717 .mac_link_up = xrs700x_mac_link_up,718};719 720static const struct dsa_switch_ops xrs700x_ops = {721 .get_tag_protocol = xrs700x_get_tag_protocol,722 .setup = xrs700x_setup,723 .teardown = xrs700x_teardown,724 .port_stp_state_set = xrs700x_port_stp_state_set,725 .phylink_get_caps = xrs700x_phylink_get_caps,726 .get_strings = xrs700x_get_strings,727 .get_sset_count = xrs700x_get_sset_count,728 .get_ethtool_stats = xrs700x_get_ethtool_stats,729 .get_stats64 = xrs700x_get_stats64,730 .port_bridge_join = xrs700x_bridge_join,731 .port_bridge_leave = xrs700x_bridge_leave,732 .port_hsr_join = xrs700x_hsr_join,733 .port_hsr_leave = xrs700x_hsr_leave,734};735 736static int xrs700x_detect(struct xrs700x *priv)737{738 const struct xrs700x_info *info;739 unsigned int id;740 int ret;741 742 ret = regmap_read(priv->regmap, XRS_DEV_ID0, &id);743 if (ret) {744 dev_err(priv->dev, "error %d while reading switch id.\n",745 ret);746 return ret;747 }748 749 info = of_device_get_match_data(priv->dev);750 if (!info)751 return -EINVAL;752 753 if (info->id == id) {754 priv->ds->num_ports = info->num_ports;755 dev_info(priv->dev, "%s detected.\n", info->name);756 return 0;757 }758 759 dev_err(priv->dev, "expected switch id 0x%x but found 0x%x.\n",760 info->id, id);761 762 return -ENODEV;763}764 765struct xrs700x *xrs700x_switch_alloc(struct device *base, void *devpriv)766{767 struct dsa_switch *ds;768 struct xrs700x *priv;769 770 ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL);771 if (!ds)772 return NULL;773 774 ds->dev = base;775 776 priv = devm_kzalloc(base, sizeof(*priv), GFP_KERNEL);777 if (!priv)778 return NULL;779 780 INIT_DELAYED_WORK(&priv->mib_work, xrs700x_mib_work);781 782 ds->ops = &xrs700x_ops;783 ds->phylink_mac_ops = &xrs700x_phylink_mac_ops;784 ds->priv = priv;785 priv->dev = base;786 787 priv->ds = ds;788 priv->priv = devpriv;789 790 return priv;791}792EXPORT_SYMBOL(xrs700x_switch_alloc);793 794static int xrs700x_alloc_port_mib(struct xrs700x *priv, int port)795{796 struct xrs700x_port *p = &priv->ports[port];797 798 p->mib_data = devm_kcalloc(priv->dev, ARRAY_SIZE(xrs700x_mibs),799 sizeof(*p->mib_data), GFP_KERNEL);800 if (!p->mib_data)801 return -ENOMEM;802 803 mutex_init(&p->mib_mutex);804 u64_stats_init(&p->syncp);805 806 return 0;807}808 809int xrs700x_switch_register(struct xrs700x *priv)810{811 int ret;812 int i;813 814 ret = xrs700x_detect(priv);815 if (ret)816 return ret;817 818 ret = xrs700x_setup_regmap_range(priv);819 if (ret)820 return ret;821 822 priv->ports = devm_kcalloc(priv->dev, priv->ds->num_ports,823 sizeof(*priv->ports), GFP_KERNEL);824 if (!priv->ports)825 return -ENOMEM;826 827 for (i = 0; i < priv->ds->num_ports; i++) {828 ret = xrs700x_alloc_port_mib(priv, i);829 if (ret)830 return ret;831 }832 833 return dsa_register_switch(priv->ds);834}835EXPORT_SYMBOL(xrs700x_switch_register);836 837void xrs700x_switch_remove(struct xrs700x *priv)838{839 dsa_unregister_switch(priv->ds);840}841EXPORT_SYMBOL(xrs700x_switch_remove);842 843void xrs700x_switch_shutdown(struct xrs700x *priv)844{845 dsa_switch_shutdown(priv->ds);846}847EXPORT_SYMBOL(xrs700x_switch_shutdown);848 849MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");850MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA driver");851MODULE_LICENSE("GPL v2");852