Skip to content

Commit 461cd1b

Browse files
ffainellidavem330
authored andcommitted
net: dsa: bcm_sf2: Register our slave MDIO bus
Register a slave MDIO bus which allows us to divert problematic read/writes towards conflicting pseudo-PHY address (30). Do no longer rely on DSA's slave_mii_bus, but instead provide our own implementation which offers more flexibility as to what to do, and when to register it. We need to register it by the time we are able to get access to our memory mapped registers, which is not until drv->setup() time. In order to avoid forward declarations, we need to re-order the function bodies a bit. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0c73c52 commit 461cd1b

File tree

2 files changed

+140
-81
lines changed

2 files changed

+140
-81
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 {

0 commit comments

Comments
 (0)