net: dsa: mv88e6xxx: create serdes_get_lane chip operation

Create a serdes_get_lane() method in the mv88e6xxx operations structure.
Use it instead of calling the different implementations.
Also change the methods so that their return value is used only for
error. The lane number is put into a place referred to by a pointer
given as argument. If the port does not have a lane, return -ENODEV.
Lanes are phy addresses, so use u8 as their type.

Signed-off-by: Marek Behún <marek.behun@nic.cz>
Reviewed-by: Vivien Didelot <vivien.didelot@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Marek Behún 2019-08-26 23:31:52 +02:00 committed by David S. Miller
parent 609070133a
commit 17deaf5cb3
5 changed files with 146 additions and 96 deletions

View File

@ -3255,6 +3255,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
@ -3301,6 +3302,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390x_serdes_power,
.serdes_get_lane = mv88e6390x_serdes_get_lane,
.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
.serdes_irq_free = mv88e6390x_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
@ -3347,6 +3349,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.avb_ops = &mv88e6390_avb_ops,
@ -3483,6 +3486,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
@ -3800,6 +3804,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
.serdes_get_lane = mv88e6390_serdes_get_lane,
.serdes_irq_setup = mv88e6390_serdes_irq_setup,
.serdes_irq_free = mv88e6390_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,
@ -3850,6 +3855,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390x_serdes_power,
.serdes_get_lane = mv88e6390x_serdes_get_lane,
.serdes_irq_setup = mv88e6390x_serdes_irq_setup,
.serdes_irq_free = mv88e6390x_serdes_irq_free,
.gpio_ops = &mv88e6352_gpio_ops,

View File

@ -443,6 +443,9 @@ struct mv88e6xxx_ops {
/* Power on/off a SERDES interface */
int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on);
/* SERDES lane mapping */
int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port, u8 *lane);
/* SERDES interrupt handling */
int (*serdes_irq_setup)(struct mv88e6xxx_chip *chip, int port);
void (*serdes_irq_free)(struct mv88e6xxx_chip *chip, int port);

View File

@ -395,7 +395,7 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port)
int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
phy_interface_t mode)
{
int lane;
u8 lane;
u16 cmode;
u16 reg;
int err;
@ -434,11 +434,11 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
if (cmode == chip->ports[port].cmode)
return 0;
lane = mv88e6390x_serdes_get_lane(chip, port);
if (lane < 0 && lane != -ENODEV)
return lane;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err && err != -ENODEV)
return err;
if (lane >= 0) {
if (err != -ENODEV) {
if (chip->ports[port].serdes_irq) {
err = mv88e6390_serdes_irq_disable(chip, port, lane);
if (err)
@ -466,9 +466,9 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
chip->ports[port].cmode = cmode;
lane = mv88e6390x_serdes_get_lane(chip, port);
if (lane < 0)
return lane;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err)
return err;
err = mv88e6390x_serdes_power(chip, port, true);
if (err)

View File

@ -286,10 +286,7 @@ void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
chip->ports[port].serdes_irq = 0;
}
/* Return the SERDES lane address a port is using. Only Ports 9 and 10
* have SERDES lanes. Returns -ENODEV if a port does not have a lane.
*/
static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane)
{
u8 cmode = chip->ports[port].cmode;
@ -297,25 +294,27 @@ static int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
case 9:
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
return MV88E6390_PORT9_LANE0;
return -ENODEV;
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
*lane = MV88E6390_PORT9_LANE0;
return 0;
}
break;
case 10:
if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
return MV88E6390_PORT10_LANE0;
return -ENODEV;
cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
*lane = MV88E6390_PORT10_LANE0;
return 0;
}
break;
default:
return -ENODEV;
break;
}
return -ENODEV;
}
/* Return the SERDES lane address a port is using. Ports 9 and 10 can
* use multiple lanes. If so, return the first lane the port uses.
* Returns -ENODEV if a port does not have a lane.
*/
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane)
{
u8 cmode_port9, cmode_port10, cmode_port;
@ -327,72 +326,96 @@ int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port)
case 2:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
return MV88E6390_PORT9_LANE1;
return -ENODEV;
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) {
*lane = MV88E6390_PORT9_LANE1;
return 0;
}
}
break;
case 3:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
return MV88E6390_PORT9_LANE2;
return -ENODEV;
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) {
*lane = MV88E6390_PORT9_LANE2;
return 0;
}
}
break;
case 4:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
return MV88E6390_PORT9_LANE3;
return -ENODEV;
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) {
*lane = MV88E6390_PORT9_LANE3;
return 0;
}
}
break;
case 5:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX)
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
return MV88E6390_PORT10_LANE1;
return -ENODEV;
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) {
*lane = MV88E6390_PORT10_LANE1;
return 0;
}
}
break;
case 6:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
return MV88E6390_PORT10_LANE2;
return -ENODEV;
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) {
*lane = MV88E6390_PORT10_LANE2;
return 0;
}
}
break;
case 7:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X)
return MV88E6390_PORT10_LANE3;
return -ENODEV;
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASE_X) {
*lane = MV88E6390_PORT10_LANE3;
return 0;
}
}
break;
case 9:
if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
return MV88E6390_PORT9_LANE0;
return -ENODEV;
cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
*lane = MV88E6390_PORT9_LANE0;
return 0;
}
break;
case 10:
if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASE_X ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI ||
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI)
return MV88E6390_PORT10_LANE0;
return -ENODEV;
cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) {
*lane = MV88E6390_PORT10_LANE0;
return 0;
}
break;
default:
return -ENODEV;
break;
}
return -ENODEV;
}
/* Set the power on/off for 10GBASE-R and 10GBASE-X4/X2 */
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane,
bool on)
{
u16 val, new_val;
@ -419,7 +442,7 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, int lane,
}
/* Set the power on/off for SGMII and 1000Base-X */
static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane,
bool on)
{
u16 val, new_val;
@ -445,7 +468,7 @@ static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, int lane,
}
static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
int lane, bool on)
u8 lane, bool on)
{
u8 cmode = chip->ports[port].cmode;
@ -464,14 +487,15 @@ static int mv88e6390_serdes_power_lane(struct mv88e6xxx_chip *chip, int port,
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
{
int lane;
u8 lane;
int err;
lane = mv88e6390_serdes_get_lane(chip, port);
if (lane == -ENODEV)
return 0;
if (lane < 0)
return lane;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err) {
if (err == -ENODEV)
err = 0;
return err;
}
switch (port) {
case 9 ... 10:
@ -483,14 +507,15 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
{
int lane;
u8 lane;
int err;
lane = mv88e6390x_serdes_get_lane(chip, port);
if (lane == -ENODEV)
return 0;
if (lane < 0)
return lane;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err) {
if (err == -ENODEV)
err = 0;
return err;
}
switch (port) {
case 2 ... 4:
@ -503,7 +528,7 @@ int mv88e6390x_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
}
static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
int port, int lane)
int port, u8 lane)
{
u8 cmode = chip->ports[port].cmode;
struct dsa_switch *ds = chip->ds;
@ -570,7 +595,7 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip,
}
static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
int lane)
u8 lane)
{
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
MV88E6390_SGMII_INT_ENABLE,
@ -579,14 +604,14 @@ static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip,
}
static int mv88e6390_serdes_irq_disable_sgmii(struct mv88e6xxx_chip *chip,
int lane)
u8 lane)
{
return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS,
MV88E6390_SGMII_INT_ENABLE, 0);
}
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
int lane)
u8 lane)
{
u8 cmode = chip->ports[port].cmode;
int err = 0;
@ -602,7 +627,7 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
}
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
int lane)
u8 lane)
{
u8 cmode = chip->ports[port].cmode;
int err = 0;
@ -618,7 +643,7 @@ int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
}
static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip,
int lane, u16 *status)
u8 lane, u16 *status)
{
int err;
@ -635,10 +660,10 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
irqreturn_t ret = IRQ_NONE;
u8 cmode = port->cmode;
u16 status;
int lane;
int err;
u8 lane;
lane = mv88e6390x_serdes_get_lane(chip, port->port);
mv88e6xxx_serdes_get_lane(chip, port->port, &lane);
mv88e6xxx_reg_lock(chip);
@ -663,16 +688,15 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
{
int lane;
int err;
u8 lane;
lane = mv88e6390x_serdes_get_lane(chip, port);
if (lane == -ENODEV)
return 0;
if (lane < 0)
return lane;
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err) {
if (err == -ENODEV)
err = 0;
return err;
}
chip->ports[port].serdes_irq = irq_find_mapping(chip->g2_irq.domain,
port);
@ -711,13 +735,16 @@ int mv88e6390_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
{
int lane = mv88e6390x_serdes_get_lane(chip, port);
int err;
u8 lane;
if (lane == -ENODEV)
return;
if (lane < 0)
err = mv88e6xxx_serdes_get_lane(chip, port, &lane);
if (err) {
if (err != -ENODEV)
dev_err(chip->dev, "Unable to free SERDES irq: %d\n",
err);
return;
}
mv88e6390_serdes_irq_disable(chip, port, lane);

View File

@ -74,7 +74,21 @@
#define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11)
#define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10)
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port);
/* Put the SERDES lane address a port is using into *lane. If a port has
* multiple lanes, should put the first lane the port is using. If a port does
* not have a lane, return -ENODEV.
*/
static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip,
int port, u8 *lane)
{
if (!chip->info->ops->serdes_get_lane)
return -EOPNOTSUPP;
return chip->info->ops->serdes_get_lane(chip, port, lane);
}
int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane);
int mv88e6341_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
@ -89,9 +103,9 @@ int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data);
int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port,
int lane);
u8 lane);
int mv88e6390_serdes_irq_disable(struct mv88e6xxx_chip *chip, int port,
int lane);
u8 lane);
int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port);
void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port);