brintos

brintos / linux-shallow public Read only

0
0
Text · 21.2 KiB · de3b768 Raw
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