Skip to content

Commit

Permalink
net: dsa: mv88e6xxx: Replace PHY mutex by SMI mutex
Browse files Browse the repository at this point in the history
The SMI bus is the bottleneck in all switch operations, not the
granularity of locks. Replace the PHY mutex by the SMI mutex to make
the locking concept simpler.

The REG_READ/REG_WRITE macros cannot be used while holding the SMI
mutex, since they try to acquire it. Replace with calls to the
appropriate function which does not try to get the mutex.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Andrew Lunn authored and David S. Miller committed May 9, 2015
1 parent 1441f4e commit 3898c14
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 59 deletions.
121 changes: 63 additions & 58 deletions drivers/net/dsa/mv88e6xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,20 +199,20 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
return 0;
}

/* Must be called with phy mutex held */
/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_read(struct dsa_switch *ds, int addr, int regnum)
{
if (addr >= 0)
return mv88e6xxx_reg_read(ds, addr, regnum);
return _mv88e6xxx_reg_read(ds, addr, regnum);
return 0xffff;
}

/* Must be called with phy mutex held */
/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum,
u16 val)
{
if (addr >= 0)
return mv88e6xxx_reg_write(ds, addr, regnum, val);
return _mv88e6xxx_reg_write(ds, addr, regnum, val);
return 0;
}

Expand Down Expand Up @@ -762,7 +762,7 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)

*temp = 0;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);

ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6);
if (ret < 0)
Expand Down Expand Up @@ -795,19 +795,23 @@ int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp)

error:
_mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0);
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return ret;
}
#endif /* CONFIG_NET_DSA_HWMON */

static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
/* Must be called with SMI lock held */
static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset,
u16 mask)
{
unsigned long timeout = jiffies + HZ / 10;

while (time_before(jiffies, timeout)) {
int ret;

ret = REG_READ(reg, offset);
ret = _mv88e6xxx_reg_read(ds, reg, offset);
if (ret < 0)
return ret;
if (!(ret & mask))
return 0;

Expand All @@ -816,10 +820,22 @@ static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
return -ETIMEDOUT;
}

int mv88e6xxx_phy_wait(struct dsa_switch *ds)
static int mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;

mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_wait(ds, reg, offset, mask);
mutex_unlock(&ps->smi_mutex);

return ret;
}

static int _mv88e6xxx_phy_wait(struct dsa_switch *ds)
{
return mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
GLOBAL2_SMI_OP_BUSY);
return _mv88e6xxx_wait(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
GLOBAL2_SMI_OP_BUSY);
}

int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds)
Expand All @@ -834,65 +850,55 @@ int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds)
GLOBAL2_EEPROM_OP_BUSY);
}

/* Must be called with SMI lock held */
static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
{
unsigned long timeout = jiffies + HZ / 10;

while (time_before(jiffies, timeout)) {
int ret;

ret = _mv88e6xxx_reg_read(ds, reg, offset);
if (ret < 0)
return ret;
if (!(ret & mask))
return 0;

usleep_range(1000, 2000);
}
return -ETIMEDOUT;
}

/* Must be called with SMI lock held */
static int _mv88e6xxx_atu_wait(struct dsa_switch *ds)
{
return _mv88e6xxx_wait(ds, REG_GLOBAL, GLOBAL_ATU_OP,
GLOBAL_ATU_OP_BUSY);
}

/* Must be called with phy mutex held */
/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr,
int regnum)
{
int ret;

REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
GLOBAL2_SMI_OP_22_READ | (addr << 5) | regnum);
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
GLOBAL2_SMI_OP_22_READ | (addr << 5) |
regnum);
if (ret < 0)
return ret;

ret = mv88e6xxx_phy_wait(ds);
ret = _mv88e6xxx_phy_wait(ds);
if (ret < 0)
return ret;

return REG_READ(REG_GLOBAL2, GLOBAL2_SMI_DATA);
return _mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA);
}

/* Must be called with phy mutex held */
/* Must be called with SMI mutex held */
static int _mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr,
int regnum, u16 val)
{
REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
REG_WRITE(REG_GLOBAL2, GLOBAL2_SMI_OP,
GLOBAL2_SMI_OP_22_WRITE | (addr << 5) | regnum);
int ret;

ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_DATA, val);
if (ret < 0)
return ret;

return mv88e6xxx_phy_wait(ds);
ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_SMI_OP,
GLOBAL2_SMI_OP_22_WRITE | (addr << 5) |
regnum);

return _mv88e6xxx_phy_wait(ds);
}

int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int reg;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);

reg = _mv88e6xxx_phy_read_indirect(ds, port, 16);
if (reg < 0)
Expand All @@ -901,15 +907,15 @@ int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
e->eee_enabled = !!(reg & 0x0200);
e->tx_lpi_enabled = !!(reg & 0x0100);

reg = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_STATUS);
if (reg < 0)
goto out;

e->eee_active = !!(reg & PORT_STATUS_EEE);
reg = 0;

out:
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return reg;
}

Expand All @@ -920,7 +926,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
int reg;
int ret;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);

ret = _mv88e6xxx_phy_read_indirect(ds, port, 16);
if (ret < 0)
Expand All @@ -934,7 +940,7 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,

ret = _mv88e6xxx_phy_write_indirect(ds, port, 16, reg);
out:
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);

return ret;
}
Expand Down Expand Up @@ -1568,7 +1574,6 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds)

mutex_init(&ps->smi_mutex);
mutex_init(&ps->stats_mutex);
mutex_init(&ps->phy_mutex);

ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0;

Expand Down Expand Up @@ -1722,14 +1727,14 @@ int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg)
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;
ret = _mv88e6xxx_phy_read_indirect(ds, port, reg);
error:
_mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return ret;
}

Expand All @@ -1739,15 +1744,15 @@ int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
int ret;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write_indirect(ds, port, 0x16, page);
if (ret < 0)
goto error;

ret = _mv88e6xxx_phy_write_indirect(ds, port, reg, val);
error:
_mv88e6xxx_phy_write_indirect(ds, port, 0x16, 0x0);
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return ret;
}

Expand All @@ -1770,9 +1775,9 @@ mv88e6xxx_phy_read(struct dsa_switch *ds, int port, int regnum)
if (addr < 0)
return addr;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_read(ds, addr, regnum);
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return ret;
}

Expand All @@ -1786,9 +1791,9 @@ mv88e6xxx_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
if (addr < 0)
return addr;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write(ds, addr, regnum, val);
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return ret;
}

Expand All @@ -1802,9 +1807,9 @@ mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int port, int regnum)
if (addr < 0)
return addr;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_read_indirect(ds, addr, regnum);
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return ret;
}

Expand All @@ -1819,9 +1824,9 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum,
if (addr < 0)
return addr;

mutex_lock(&ps->phy_mutex);
mutex_lock(&ps->smi_mutex);
ret = _mv88e6xxx_phy_write_indirect(ds, addr, regnum, val);
mutex_unlock(&ps->phy_mutex);
mutex_unlock(&ps->smi_mutex);
return ret;
}

Expand Down
1 change: 0 additions & 1 deletion drivers/net/dsa/mv88e6xxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,6 @@ int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port);
void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
struct ethtool_regs *regs, void *_p);
int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp);
int mv88e6xxx_phy_wait(struct dsa_switch *ds);
int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds);
int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds);
int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum);
Expand Down

0 comments on commit 3898c14

Please sign in to comment.