Merge branch 'dsa-lan9303-Fix-MDIO-issues'

Egil Hjelmeland says:

====================
net: dsa: lan9303: Fix MDIO issues.

This series fix the MDIO interface for the lan9303 DSA driver.
Bugs found after testing on actual HW.

This series is extracted from the first patch of my first large
series. Significant changes from that version are:
 - use mdiobus_write_nested, mdiobus_read_nested.
 - EXPORT lan9303_indirect_phy_ops

Unfortunately I do not have access to i2c based system for
testing.

Changes from first version:
 - Change EXPORT_SYMBOL to EXPORT_SYMBOL_GPL
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-07-30 19:23:29 -07:00
commit 509394e841
4 changed files with 64 additions and 15 deletions

View File

@ -20,6 +20,9 @@
#include "lan9303.h"
/* 13.2 System Control and Status Registers
* Multiply register number by 4 to get address offset.
*/
#define LAN9303_CHIP_REV 0x14
# define LAN9303_CHIP_ID 0x9303
#define LAN9303_IRQ_CFG 0x15
@ -53,6 +56,9 @@
#define LAN9303_VIRT_PHY_BASE 0x70
#define LAN9303_VIRT_SPECIAL_CTRL 0x77
/*13.4 Switch Fabric Control and Status Registers
* Accessed indirectly via SWITCH_CSR_CMD, SWITCH_CSR_DATA.
*/
#define LAN9303_SW_DEV_ID 0x0000
#define LAN9303_SW_RESET 0x0001
#define LAN9303_SW_RESET_RESET BIT(0)
@ -242,7 +248,7 @@ static int lan9303_virt_phy_reg_write(struct lan9303 *chip, int regnum, u16 val)
return regmap_write(chip->regmap, LAN9303_VIRT_PHY_BASE + regnum, val);
}
static int lan9303_port_phy_reg_wait_for_completion(struct lan9303 *chip)
static int lan9303_indirect_phy_wait_for_completion(struct lan9303 *chip)
{
int ret, i;
u32 reg;
@ -262,7 +268,7 @@ static int lan9303_port_phy_reg_wait_for_completion(struct lan9303 *chip)
return -EIO;
}
static int lan9303_port_phy_reg_read(struct lan9303 *chip, int addr, int regnum)
static int lan9303_indirect_phy_read(struct lan9303 *chip, int addr, int regnum)
{
int ret;
u32 val;
@ -272,7 +278,7 @@ static int lan9303_port_phy_reg_read(struct lan9303 *chip, int addr, int regnum)
mutex_lock(&chip->indirect_mutex);
ret = lan9303_port_phy_reg_wait_for_completion(chip);
ret = lan9303_indirect_phy_wait_for_completion(chip);
if (ret)
goto on_error;
@ -281,7 +287,7 @@ static int lan9303_port_phy_reg_read(struct lan9303 *chip, int addr, int regnum)
if (ret)
goto on_error;
ret = lan9303_port_phy_reg_wait_for_completion(chip);
ret = lan9303_indirect_phy_wait_for_completion(chip);
if (ret)
goto on_error;
@ -299,8 +305,8 @@ on_error:
return ret;
}
static int lan9303_phy_reg_write(struct lan9303 *chip, int addr, int regnum,
unsigned int val)
static int lan9303_indirect_phy_write(struct lan9303 *chip, int addr,
int regnum, u16 val)
{
int ret;
u32 reg;
@ -311,7 +317,7 @@ static int lan9303_phy_reg_write(struct lan9303 *chip, int addr, int regnum,
mutex_lock(&chip->indirect_mutex);
ret = lan9303_port_phy_reg_wait_for_completion(chip);
ret = lan9303_indirect_phy_wait_for_completion(chip);
if (ret)
goto on_error;
@ -328,6 +334,12 @@ on_error:
return ret;
}
const struct lan9303_phy_ops lan9303_indirect_phy_ops = {
.phy_read = lan9303_indirect_phy_read,
.phy_write = lan9303_indirect_phy_write,
};
EXPORT_SYMBOL_GPL(lan9303_indirect_phy_ops);
static int lan9303_switch_wait_for_completion(struct lan9303 *chip)
{
int ret, i;
@ -427,14 +439,15 @@ static int lan9303_detect_phy_setup(struct lan9303 *chip)
* Special reg 18 of phy 3 reads as 0x0000, if 'phy_addr_sel_strap' is 0
* and the IDs are 0-1-2, else it contains something different from
* 0x0000, which means 'phy_addr_sel_strap' is 1 and the IDs are 1-2-3.
* 0xffff is returned on MDIO read with no response.
*/
reg = lan9303_port_phy_reg_read(chip, 3, MII_LAN911X_SPECIAL_MODES);
reg = chip->ops->phy_read(chip, 3, MII_LAN911X_SPECIAL_MODES);
if (reg < 0) {
dev_err(chip->dev, "Failed to detect phy config: %d\n", reg);
return reg;
}
if (reg != 0)
if ((reg != 0) && (reg != 0xffff))
chip->phy_addr_sel_strap = 1;
else
chip->phy_addr_sel_strap = 0;
@ -719,7 +732,7 @@ static int lan9303_phy_read(struct dsa_switch *ds, int phy, int regnum)
if (phy > phy_base + 2)
return -ENODEV;
return lan9303_port_phy_reg_read(chip, phy, regnum);
return chip->ops->phy_read(chip, phy, regnum);
}
static int lan9303_phy_write(struct dsa_switch *ds, int phy, int regnum,
@ -733,7 +746,7 @@ static int lan9303_phy_write(struct dsa_switch *ds, int phy, int regnum,
if (phy > phy_base + 2)
return -ENODEV;
return lan9303_phy_reg_write(chip, phy, regnum, val);
return chip->ops->phy_write(chip, phy, regnum, val);
}
static int lan9303_port_enable(struct dsa_switch *ds, int port,
@ -766,13 +779,13 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port,
switch (port) {
case 1:
lan9303_disable_packet_processing(chip, LAN9303_PORT_1_OFFSET);
lan9303_phy_reg_write(chip, chip->phy_addr_sel_strap + 1,
MII_BMCR, BMCR_PDOWN);
lan9303_phy_write(ds, chip->phy_addr_sel_strap + 1,
MII_BMCR, BMCR_PDOWN);
break;
case 2:
lan9303_disable_packet_processing(chip, LAN9303_PORT_2_OFFSET);
lan9303_phy_reg_write(chip, chip->phy_addr_sel_strap + 2,
MII_BMCR, BMCR_PDOWN);
lan9303_phy_write(ds, chip->phy_addr_sel_strap + 2,
MII_BMCR, BMCR_PDOWN);
break;
default:
dev_dbg(chip->dev,

View File

@ -2,6 +2,15 @@
#include <linux/device.h>
#include <net/dsa.h>
struct lan9303;
struct lan9303_phy_ops {
/* PHY 1 and 2 access*/
int (*phy_read)(struct lan9303 *chip, int port, int regnum);
int (*phy_write)(struct lan9303 *chip, int port,
int regnum, u16 val);
};
struct lan9303 {
struct device *dev;
struct regmap *regmap;
@ -11,9 +20,11 @@ struct lan9303 {
bool phy_addr_sel_strap;
struct dsa_switch *ds;
struct mutex indirect_mutex; /* protect indexed register access */
const struct lan9303_phy_ops *ops;
};
extern const struct regmap_access_table lan9303_register_set;
extern const struct lan9303_phy_ops lan9303_indirect_phy_ops;
int lan9303_probe(struct lan9303 *chip, struct device_node *np);
int lan9303_remove(struct lan9303 *chip);

View File

@ -63,6 +63,8 @@ static int lan9303_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, sw_dev);
sw_dev->chip.dev = &client->dev;
sw_dev->chip.ops = &lan9303_indirect_phy_ops;
ret = lan9303_probe(&sw_dev->chip, client->dev.of_node);
if (ret != 0)
return ret;

View File

@ -40,6 +40,7 @@ static int lan9303_mdio_write(void *ctx, uint32_t reg, uint32_t val)
{
struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
reg <<= 2; /* reg num to offset */
mutex_lock(&sw_dev->device->bus->mdio_lock);
lan9303_mdio_real_write(sw_dev->device, reg, val & 0xffff);
lan9303_mdio_real_write(sw_dev->device, reg + 2, (val >> 16) & 0xffff);
@ -57,6 +58,7 @@ static int lan9303_mdio_read(void *ctx, uint32_t reg, uint32_t *val)
{
struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx;
reg <<= 2; /* reg num to offset */
mutex_lock(&sw_dev->device->bus->mdio_lock);
*val = lan9303_mdio_real_read(sw_dev->device, reg);
*val |= (lan9303_mdio_real_read(sw_dev->device, reg + 2) << 16);
@ -65,6 +67,25 @@ static int lan9303_mdio_read(void *ctx, uint32_t reg, uint32_t *val)
return 0;
}
int lan9303_mdio_phy_write(struct lan9303 *chip, int phy, int reg, u16 val)
{
struct lan9303_mdio *sw_dev = dev_get_drvdata(chip->dev);
return mdiobus_write_nested(sw_dev->device->bus, phy, reg, val);
}
int lan9303_mdio_phy_read(struct lan9303 *chip, int phy, int reg)
{
struct lan9303_mdio *sw_dev = dev_get_drvdata(chip->dev);
return mdiobus_read_nested(sw_dev->device->bus, phy, reg);
}
static const struct lan9303_phy_ops lan9303_mdio_phy_ops = {
.phy_read = lan9303_mdio_phy_read,
.phy_write = lan9303_mdio_phy_write,
};
static const struct regmap_config lan9303_mdio_regmap_config = {
.reg_bits = 8,
.val_bits = 32,
@ -106,6 +127,8 @@ static int lan9303_mdio_probe(struct mdio_device *mdiodev)
dev_set_drvdata(&mdiodev->dev, sw_dev);
sw_dev->chip.dev = &mdiodev->dev;
sw_dev->chip.ops = &lan9303_mdio_phy_ops;
ret = lan9303_probe(&sw_dev->chip, mdiodev->dev.of_node);
if (ret != 0)
return ret;