Skip to content

Commit 8fa956e

Browse files
committed
Merge branch 'dsa-misc-improvements'
Florian Fainelli says: ==================== net: dsa: misc improvements This patch series builds on top of Andrew's "New DSA bind, switches as devices" patch set and does the following: - add a few helper functions/goodies for net/dsa/dsa2.c to be as close as possible from net/dsa/dsa.c in terms of what drivers can expect, in particular the slave MDIO bus and the enabled_port_mask and phy_mii_mask - fix the CPU port ethtools ops to work in a multiple tree setup since we can no longer assume a single tree is supported - make the bcm_sf2 driver register its own MDIO bus, yet assign it to ds->slave_mii_bus for everything to work in net/dsa/slave.c wrt. PHY probing, this is a tad cleaner than what we have now Changes in v2: Most of the previous patches have been dropped to just keep the relevant ones now. Changes in v3: - split the addition of the slave MII bus as a separate patch - properly unwind all operations at the right place and right time (ethtool ops, slave MDIO bus - fixed a few typos here and there Changes in v4: - removed superfluous dst agrument to dsa_cpu_port_ethtool_{setup,restore} ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 123b365 + 461cd1b commit 8fa956e

File tree

7 files changed

+230
-97
lines changed

7 files changed

+230
-97
lines changed

drivers/net/dsa/bcm_sf2.c

Lines changed: 134 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/of_irq.h>
2323
#include <linux/of_address.h>
2424
#include <linux/of_net.h>
25+
#include <linux/of_mdio.h>
2526
#include <net/dsa.h>
2627
#include <linux/ethtool.h>
2728
#include <linux/if_bridge.h>
@@ -836,6 +837,66 @@ static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
836837
return 0;
837838
}
838839

840+
static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr,
841+
int regnum, u16 val)
842+
{
843+
int ret = 0;
844+
u32 reg;
845+
846+
reg = reg_readl(priv, REG_SWITCH_CNTRL);
847+
reg |= MDIO_MASTER_SEL;
848+
reg_writel(priv, reg, REG_SWITCH_CNTRL);
849+
850+
/* Page << 8 | offset */
851+
reg = 0x70;
852+
reg <<= 2;
853+
core_writel(priv, addr, reg);
854+
855+
/* Page << 8 | offset */
856+
reg = 0x80 << 8 | regnum << 1;
857+
reg <<= 2;
858+
859+
if (op)
860+
ret = core_readl(priv, reg);
861+
else
862+
core_writel(priv, val, reg);
863+
864+
reg = reg_readl(priv, REG_SWITCH_CNTRL);
865+
reg &= ~MDIO_MASTER_SEL;
866+
reg_writel(priv, reg, REG_SWITCH_CNTRL);
867+
868+
return ret & 0xffff;
869+
}
870+
871+
static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
872+
{
873+
struct bcm_sf2_priv *priv = bus->priv;
874+
875+
/* Intercept reads from Broadcom pseudo-PHY address, else, send
876+
* them to our master MDIO bus controller
877+
*/
878+
if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
879+
return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0);
880+
else
881+
return mdiobus_read(priv->master_mii_bus, addr, regnum);
882+
}
883+
884+
static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
885+
u16 val)
886+
{
887+
struct bcm_sf2_priv *priv = bus->priv;
888+
889+
/* Intercept writes to the Broadcom pseudo-PHY address, else,
890+
* send them to our master MDIO bus controller
891+
*/
892+
if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
893+
bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val);
894+
else
895+
mdiobus_write(priv->master_mii_bus, addr, regnum, val);
896+
897+
return 0;
898+
}
899+
839900
static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
840901
{
841902
struct bcm_sf2_priv *priv = dev_id;
@@ -932,6 +993,72 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,
932993
}
933994
}
934995

996+
static int bcm_sf2_mdio_register(struct dsa_switch *ds)
997+
{
998+
struct bcm_sf2_priv *priv = ds_to_priv(ds);
999+
struct device_node *dn;
1000+
static int index;
1001+
int err;
1002+
1003+
/* Find our integrated MDIO bus node */
1004+
dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
1005+
priv->master_mii_bus = of_mdio_find_bus(dn);
1006+
if (!priv->master_mii_bus)
1007+
return -EPROBE_DEFER;
1008+
1009+
get_device(&priv->master_mii_bus->dev);
1010+
priv->master_mii_dn = dn;
1011+
1012+
priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
1013+
if (!priv->slave_mii_bus)
1014+
return -ENOMEM;
1015+
1016+
priv->slave_mii_bus->priv = priv;
1017+
priv->slave_mii_bus->name = "sf2 slave mii";
1018+
priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read;
1019+
priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write;
1020+
snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d",
1021+
index++);
1022+
priv->slave_mii_bus->dev.of_node = dn;
1023+
1024+
/* Include the pseudo-PHY address to divert reads towards our
1025+
* workaround. This is only required for 7445D0, since 7445E0
1026+
* disconnects the internal switch pseudo-PHY such that we can use the
1027+
* regular SWITCH_MDIO master controller instead.
1028+
*
1029+
* Here we flag the pseudo PHY as needing special treatment and would
1030+
* otherwise make all other PHY read/writes go to the master MDIO bus
1031+
* controller that comes with this switch backed by the "mdio-unimac"
1032+
* driver.
1033+
*/
1034+
if (of_machine_is_compatible("brcm,bcm7445d0"))
1035+
priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR);
1036+
else
1037+
priv->indir_phy_mask = 0;
1038+
1039+
ds->phys_mii_mask = priv->indir_phy_mask;
1040+
ds->slave_mii_bus = priv->slave_mii_bus;
1041+
priv->slave_mii_bus->parent = ds->dev->parent;
1042+
priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask;
1043+
1044+
if (dn)
1045+
err = of_mdiobus_register(priv->slave_mii_bus, dn);
1046+
else
1047+
err = mdiobus_register(priv->slave_mii_bus);
1048+
1049+
if (err)
1050+
of_node_put(dn);
1051+
1052+
return err;
1053+
}
1054+
1055+
static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
1056+
{
1057+
mdiobus_unregister(priv->slave_mii_bus);
1058+
if (priv->master_mii_dn)
1059+
of_node_put(priv->master_mii_dn);
1060+
}
1061+
9351062
static int bcm_sf2_sw_setup(struct dsa_switch *ds)
9361063
{
9371064
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
@@ -972,6 +1099,12 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
9721099
goto out_unmap;
9731100
}
9741101

1102+
ret = bcm_sf2_mdio_register(ds);
1103+
if (ret) {
1104+
pr_err("failed to register MDIO bus\n");
1105+
goto out_unmap;
1106+
}
1107+
9751108
/* Disable all interrupts and request them */
9761109
bcm_sf2_intr_disable(priv);
9771110

@@ -1017,23 +1150,6 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
10171150
bcm_sf2_port_disable(ds, port, NULL);
10181151
}
10191152

1020-
/* Include the pseudo-PHY address and the broadcast PHY address to
1021-
* divert reads towards our workaround. This is only required for
1022-
* 7445D0, since 7445E0 disconnects the internal switch pseudo-PHY such
1023-
* that we can use the regular SWITCH_MDIO master controller instead.
1024-
*
1025-
* By default, DSA initializes ds->phys_mii_mask to
1026-
* ds->enabled_port_mask to have a 1:1 mapping between Port address
1027-
* and PHY address in order to utilize the slave_mii_bus instance to
1028-
* read from Port PHYs. This is not what we want here, so we
1029-
* initialize phys_mii_mask 0 to always utilize the "master" MDIO
1030-
* bus backed by the "mdio-unimac" driver.
1031-
*/
1032-
if (of_machine_is_compatible("brcm,bcm7445d0"))
1033-
ds->phys_mii_mask |= ((1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0));
1034-
else
1035-
ds->phys_mii_mask = 0;
1036-
10371153
rev = reg_readl(priv, REG_SWITCH_REVISION);
10381154
priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
10391155
SWITCH_TOP_REV_MASK;
@@ -1058,6 +1174,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
10581174
iounmap(*base);
10591175
base++;
10601176
}
1177+
bcm_sf2_mdio_unregister(priv);
10611178
return ret;
10621179
}
10631180

@@ -1078,68 +1195,6 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
10781195
return priv->hw_params.gphy_rev;
10791196
}
10801197

1081-
static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
1082-
int regnum, u16 val)
1083-
{
1084-
struct bcm_sf2_priv *priv = ds_to_priv(ds);
1085-
int ret = 0;
1086-
u32 reg;
1087-
1088-
reg = reg_readl(priv, REG_SWITCH_CNTRL);
1089-
reg |= MDIO_MASTER_SEL;
1090-
reg_writel(priv, reg, REG_SWITCH_CNTRL);
1091-
1092-
/* Page << 8 | offset */
1093-
reg = 0x70;
1094-
reg <<= 2;
1095-
core_writel(priv, addr, reg);
1096-
1097-
/* Page << 8 | offset */
1098-
reg = 0x80 << 8 | regnum << 1;
1099-
reg <<= 2;
1100-
1101-
if (op)
1102-
ret = core_readl(priv, reg);
1103-
else
1104-
core_writel(priv, val, reg);
1105-
1106-
reg = reg_readl(priv, REG_SWITCH_CNTRL);
1107-
reg &= ~MDIO_MASTER_SEL;
1108-
reg_writel(priv, reg, REG_SWITCH_CNTRL);
1109-
1110-
return ret & 0xffff;
1111-
}
1112-
1113-
static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum)
1114-
{
1115-
/* Intercept reads from the MDIO broadcast address or Broadcom
1116-
* pseudo-PHY address
1117-
*/
1118-
switch (addr) {
1119-
case 0:
1120-
case BRCM_PSEUDO_PHY_ADDR:
1121-
return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0);
1122-
default:
1123-
return 0xffff;
1124-
}
1125-
}
1126-
1127-
static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum,
1128-
u16 val)
1129-
{
1130-
/* Intercept writes to the MDIO broadcast address or Broadcom
1131-
* pseudo-PHY address
1132-
*/
1133-
switch (addr) {
1134-
case 0:
1135-
case BRCM_PSEUDO_PHY_ADDR:
1136-
bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val);
1137-
break;
1138-
}
1139-
1140-
return 0;
1141-
}
1142-
11431198
static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
11441199
struct phy_device *phydev)
11451200
{
@@ -1376,8 +1431,6 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
13761431
.setup = bcm_sf2_sw_setup,
13771432
.set_addr = bcm_sf2_sw_set_addr,
13781433
.get_phy_flags = bcm_sf2_sw_get_phy_flags,
1379-
.phy_read = bcm_sf2_sw_phy_read,
1380-
.phy_write = bcm_sf2_sw_phy_write,
13811434
.get_strings = bcm_sf2_sw_get_strings,
13821435
.get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats,
13831436
.get_sset_count = bcm_sf2_sw_get_sset_count,

drivers/net/dsa/bcm_sf2.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ struct bcm_sf2_priv {
142142

143143
/* Bitmask of ports having an integrated PHY */
144144
unsigned int int_phy_mask;
145+
146+
/* Master and slave MDIO bus controller */
147+
unsigned int indir_phy_mask;
148+
struct device_node *master_mii_dn;
149+
struct mii_bus *slave_mii_bus;
150+
struct mii_bus *master_mii_bus;
145151
};
146152

147153
struct bcm_sf2_hw_stats {

include/net/dsa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct dsa_switch_tree {
116116
* Original copy of the master netdev ethtool_ops
117117
*/
118118
struct ethtool_ops master_ethtool_ops;
119+
const struct ethtool_ops *master_orig_ethtool_ops;
119120

120121
/*
121122
* The switch and port to which the CPU is attached.

net/dsa/dsa.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,41 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol)
266266
return ops;
267267
}
268268

269+
int dsa_cpu_port_ethtool_setup(struct dsa_switch *ds)
270+
{
271+
struct net_device *master;
272+
struct ethtool_ops *cpu_ops;
273+
274+
master = ds->dst->master_netdev;
275+
if (ds->master_netdev)
276+
master = ds->master_netdev;
277+
278+
cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL);
279+
if (!cpu_ops)
280+
return -ENOMEM;
281+
282+
memcpy(&ds->dst->master_ethtool_ops, master->ethtool_ops,
283+
sizeof(struct ethtool_ops));
284+
ds->dst->master_orig_ethtool_ops = master->ethtool_ops;
285+
memcpy(cpu_ops, &ds->dst->master_ethtool_ops,
286+
sizeof(struct ethtool_ops));
287+
dsa_cpu_port_ethtool_init(cpu_ops);
288+
master->ethtool_ops = cpu_ops;
289+
290+
return 0;
291+
}
292+
293+
void dsa_cpu_port_ethtool_restore(struct dsa_switch *ds)
294+
{
295+
struct net_device *master;
296+
297+
master = ds->dst->master_netdev;
298+
if (ds->master_netdev)
299+
master = ds->master_netdev;
300+
301+
master->ethtool_ops = ds->dst->master_orig_ethtool_ops;
302+
}
303+
269304
static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
270305
{
271306
struct dsa_switch_driver *drv = ds->drv;
@@ -379,6 +414,10 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)
379414
ret = 0;
380415
}
381416

417+
ret = dsa_cpu_port_ethtool_setup(ds);
418+
if (ret)
419+
return ret;
420+
382421
#ifdef CONFIG_NET_DSA_HWMON
383422
/* If the switch provides a temperature sensor,
384423
* register with hardware monitoring subsystem.
@@ -963,6 +1002,8 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
9631002
dsa_switch_destroy(ds);
9641003
}
9651004

1005+
dsa_cpu_port_ethtool_restore(dst->ds[0]);
1006+
9661007
dev_put(dst->master_netdev);
9671008
}
9681009

0 commit comments

Comments
 (0)