Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Distributed Switch Architecture loopback driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2016, Florian Fainelli <f.fainelli@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/phy_fixed.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/ethtool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/if_bridge.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/dsa/loop.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <net/dsa.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include "dsa_loop.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) static struct dsa_loop_mib_entry dsa_loop_mibs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 	[DSA_LOOP_PHY_READ_OK]	= { "phy_read_ok", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	[DSA_LOOP_PHY_READ_ERR]	= { "phy_read_err", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 	[DSA_LOOP_PHY_WRITE_OK] = { "phy_write_ok", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	[DSA_LOOP_PHY_WRITE_ERR] = { "phy_write_err", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) static struct phy_device *phydevs[PHY_MAX_ADDR];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) enum dsa_loop_devlink_resource_id {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	DSA_LOOP_DEVLINK_PARAM_ID_VTU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) static u64 dsa_loop_devlink_vtu_get(void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	struct dsa_loop_priv *ps = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	unsigned int i, count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct dsa_loop_vlan *vl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	for (i = 0; i < ARRAY_SIZE(ps->vlans); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 		vl = &ps->vlans[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 		if (vl->members)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) static int dsa_loop_setup_devlink_resources(struct dsa_switch *ds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	struct devlink_resource_size_params size_params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	devlink_resource_size_params_init(&size_params, ARRAY_SIZE(ps->vlans),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 					  ARRAY_SIZE(ps->vlans),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	err = dsa_devlink_resource_register(ds, "VTU", ARRAY_SIZE(ps->vlans),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 					    DSA_LOOP_DEVLINK_PARAM_ID_VTU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 					    DEVLINK_RESOURCE_ID_PARENT_TOP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 					    &size_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	dsa_devlink_resource_occ_get_register(ds,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 					      DSA_LOOP_DEVLINK_PARAM_ID_VTU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 					      dsa_loop_devlink_vtu_get, ps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	dsa_devlink_resources_unregister(ds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 						   int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 						   enum dsa_tag_protocol mp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	dev_dbg(ds->dev, "%s: port: %d\n", __func__, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	return DSA_TAG_PROTO_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) static int dsa_loop_setup(struct dsa_switch *ds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	for (i = 0; i < ds->num_ports; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		memcpy(ps->ports[i].mib, dsa_loop_mibs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		       sizeof(dsa_loop_mibs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	dev_dbg(ds->dev, "%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	return dsa_loop_setup_devlink_resources(ds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static void dsa_loop_teardown(struct dsa_switch *ds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	dsa_devlink_resources_unregister(ds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	if (sset != ETH_SS_STATS && sset != ETH_SS_PHY_STATS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	return __DSA_LOOP_CNT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void dsa_loop_get_strings(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 				 u32 stringset, uint8_t *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	if (stringset != ETH_SS_STATS && stringset != ETH_SS_PHY_STATS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	for (i = 0; i < __DSA_LOOP_CNT_MAX; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		memcpy(data + i * ETH_GSTRING_LEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		       ps->ports[port].mib[i].name, ETH_GSTRING_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 				       uint64_t *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	for (i = 0; i < __DSA_LOOP_CNT_MAX; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		data[i] = ps->ports[port].mib[i].val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	struct mii_bus *bus = ps->bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	ret = mdiobus_read_nested(bus, ps->port_base + port, regnum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		ps->ports[port].mib[DSA_LOOP_PHY_READ_ERR].val++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		ps->ports[port].mib[DSA_LOOP_PHY_READ_OK].val++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static int dsa_loop_phy_write(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 			      int regnum, u16 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	struct mii_bus *bus = ps->bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	ret = mdiobus_write_nested(bus, ps->port_base + port, regnum, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		ps->ports[port].mib[DSA_LOOP_PHY_WRITE_ERR].val++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		ps->ports[port].mib[DSA_LOOP_PHY_WRITE_OK].val++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 				     struct net_device *bridge)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		__func__, port, bridge->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 				       struct net_device *bridge)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		__func__, port, bridge->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 					u8 state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	dev_dbg(ds->dev, "%s: port: %d, state: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		__func__, port, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 					bool vlan_filtering,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 					struct switchdev_trans *trans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	dev_dbg(ds->dev, "%s: port: %d, vlan_filtering: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		__func__, port, vlan_filtering);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) dsa_loop_port_vlan_prepare(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 			   const struct switchdev_obj_port_vlan *vlan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	struct mii_bus *bus = ps->bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	dev_dbg(ds->dev, "%s: port: %d, vlan: %d-%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		__func__, port, vlan->vid_begin, vlan->vid_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	/* Just do a sleeping operation to make lockdep checks effective */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	mdiobus_read(bus, ps->port_base + port, MII_BMSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	if (vlan->vid_end > ARRAY_SIZE(ps->vlans))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static void dsa_loop_port_vlan_add(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 				   const struct switchdev_obj_port_vlan *vlan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	struct mii_bus *bus = ps->bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	struct dsa_loop_vlan *vl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	u16 vid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	/* Just do a sleeping operation to make lockdep checks effective */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	mdiobus_read(bus, ps->port_base + port, MII_BMSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 		vl = &ps->vlans[vid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		vl->members |= BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		if (untagged)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 			vl->untagged |= BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 			vl->untagged &= ~BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		dev_dbg(ds->dev, "%s: port: %d vlan: %d, %stagged, pvid: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 			__func__, port, vid, untagged ? "un" : "", pvid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	if (pvid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		ps->ports[port].pvid = vid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 				  const struct switchdev_obj_port_vlan *vlan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	struct mii_bus *bus = ps->bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	struct dsa_loop_vlan *vl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	u16 vid, pvid = ps->ports[port].pvid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	/* Just do a sleeping operation to make lockdep checks effective */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	mdiobus_read(bus, ps->port_base + port, MII_BMSR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 		vl = &ps->vlans[vid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 		vl->members &= ~BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 		if (untagged)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 			vl->untagged &= ~BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		if (pvid == vid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 			pvid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 		dev_dbg(ds->dev, "%s: port: %d vlan: %d, %stagged, pvid: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 			__func__, port, vid, untagged ? "un" : "", pvid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	ps->ports[port].pvid = pvid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static int dsa_loop_port_change_mtu(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 				    int new_mtu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	struct dsa_loop_priv *priv = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	priv->ports[port].mtu = new_mtu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) static int dsa_loop_port_max_mtu(struct dsa_switch *ds, int port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	return ETH_MAX_MTU;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static const struct dsa_switch_ops dsa_loop_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	.get_tag_protocol	= dsa_loop_get_protocol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	.setup			= dsa_loop_setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	.teardown		= dsa_loop_teardown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	.get_strings		= dsa_loop_get_strings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	.get_ethtool_stats	= dsa_loop_get_ethtool_stats,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	.get_sset_count		= dsa_loop_get_sset_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	.get_ethtool_phy_stats	= dsa_loop_get_ethtool_stats,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	.phy_read		= dsa_loop_phy_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	.phy_write		= dsa_loop_phy_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	.port_bridge_join	= dsa_loop_port_bridge_join,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	.port_bridge_leave	= dsa_loop_port_bridge_leave,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	.port_stp_state_set	= dsa_loop_port_stp_state_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	.port_vlan_filtering	= dsa_loop_port_vlan_filtering,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	.port_vlan_prepare	= dsa_loop_port_vlan_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	.port_vlan_add		= dsa_loop_port_vlan_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	.port_vlan_del		= dsa_loop_port_vlan_del,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	.port_change_mtu	= dsa_loop_port_change_mtu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	.port_max_mtu		= dsa_loop_port_max_mtu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static int dsa_loop_drv_probe(struct mdio_device *mdiodev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	struct dsa_loop_pdata *pdata = mdiodev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	struct dsa_loop_priv *ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	struct dsa_switch *ds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	if (!pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	ds = devm_kzalloc(&mdiodev->dev, sizeof(*ds), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	if (!ds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	ds->dev = &mdiodev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	ds->num_ports = DSA_LOOP_NUM_PORTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	ps = devm_kzalloc(&mdiodev->dev, sizeof(*ps), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	if (!ps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	ps->netdev = dev_get_by_name(&init_net, pdata->netdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	if (!ps->netdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	pdata->cd.netdev[DSA_LOOP_CPU_PORT] = &ps->netdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	ds->dev = &mdiodev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	ds->ops = &dsa_loop_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	ds->priv = ps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	ds->configure_vlan_while_not_filtering = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	ps->bus = mdiodev->bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	dev_set_drvdata(&mdiodev->dev, ds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	ret = dsa_register_switch(ds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		dev_info(&mdiodev->dev, "%s: 0x%0x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 			 pdata->name, pdata->enabled_ports);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static void dsa_loop_drv_remove(struct mdio_device *mdiodev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	struct dsa_loop_priv *ps = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 	dsa_unregister_switch(ds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 	dev_put(ps->netdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static struct mdio_driver dsa_loop_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	.mdiodrv.driver	= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		.name	= "dsa-loop",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 	.probe	= dsa_loop_drv_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	.remove	= dsa_loop_drv_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) #define NUM_FIXED_PHYS	(DSA_LOOP_NUM_PORTS - 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static int __init dsa_loop_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	struct fixed_phy_status status = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 		.link = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		.speed = SPEED_100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 		.duplex = DUPLEX_FULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	for (i = 0; i < NUM_FIXED_PHYS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		phydevs[i] = fixed_phy_register(PHY_POLL, &status, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	return mdio_driver_register(&dsa_loop_drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) module_init(dsa_loop_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static void __exit dsa_loop_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	mdio_driver_unregister(&dsa_loop_drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	for (i = 0; i < NUM_FIXED_PHYS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 		if (!IS_ERR(phydevs[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 			fixed_phy_unregister(phydevs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) module_exit(dsa_loop_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) MODULE_SOFTDEP("pre: dsa_loop_bdinfo");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) MODULE_AUTHOR("Florian Fainelli");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) MODULE_DESCRIPTION("DSA loopback driver");