Commit 19fb7f69 authored by Vivien Didelot's avatar Vivien Didelot Committed by David S. Miller

net: dsa: mv88e6xxx: introduce wait bit routine

Many portions of the driver need to wait until a given bit is set
or cleared. Some busses even have a specific implementation for this
operation. In preparation for such variant, implement a generic Wait
Bit routine that can be used by the driver core functions.

This allows us to get rid of the custom implementations we may find
in the driver. Note that for the EEPROM bits, BUSY and RUNNING bits
are independent, thus it is more efficient to wait independently for
each bit instead of waiting for their mask.
Signed-off-by: default avatarVivien Didelot <vivien.didelot@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 683f2244
......@@ -10,6 +10,7 @@
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
......@@ -103,6 +104,13 @@ int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
return -ETIMEDOUT;
}
int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
int bit, int val)
{
return mv88e6xxx_wait_mask(chip, addr, reg, BIT(bit),
val ? BIT(bit) : 0x0000);
}
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
{
struct mv88e6xxx_mdio_bus *mdio_bus;
......@@ -2360,8 +2368,10 @@ static int mv88e6390_hidden_write(struct mv88e6xxx_chip *chip, int port,
static int mv88e6390_hidden_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_wait(chip, PORT_RESERVED_1A_CTRL_PORT,
PORT_RESERVED_1A, PORT_RESERVED_1A_BUSY);
int bit = __bf_shf(PORT_RESERVED_1A_BUSY);
return mv88e6xxx_wait_bit(chip, PORT_RESERVED_1A_CTRL_PORT,
PORT_RESERVED_1A, bit, 0);
}
......
......@@ -592,6 +592,8 @@ int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 mask, u16 val);
int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 update);
int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg,
int bit, int val);
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask);
int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
int speed, int duplex, int pause,
......
......@@ -32,6 +32,13 @@ int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
}
int mv88e6xxx_g1_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
bit, int val)
{
return mv88e6xxx_wait_bit(chip, chip->info->global1_addr, reg,
bit, val);
}
int mv88e6xxx_g1_wait_mask(struct mv88e6xxx_chip *chip, int reg,
u16 mask, u16 val)
{
......@@ -57,49 +64,20 @@ static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip)
{
u16 state;
int i, err;
for (i = 0; i < 16; ++i) {
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state);
if (err)
return err;
/* Check the value of the PPUState (or InitState) bit 15 */
if (state & MV88E6352_G1_STS_PPU_STATE)
return 0;
int bit = __bf_shf(MV88E6352_G1_STS_PPU_STATE);
usleep_range(1000, 2000);
}
return -ETIMEDOUT;
return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STS, bit, 1);
}
static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip)
{
const unsigned long timeout = jiffies + 1 * HZ;
u16 val;
int err;
int bit = __bf_shf(MV88E6XXX_G1_STS_INIT_READY);
/* Wait up to 1 second for the switch to be ready. The InitReady bit 11
* is set to a one when all units inside the device (ATU, VTU, etc.)
* have finished their initialization and are ready to accept frames.
*/
while (time_before(jiffies, timeout)) {
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val);
if (err)
return err;
if (val & MV88E6XXX_G1_STS_INIT_READY)
break;
usleep_range(1000, 2000);
}
if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STS, bit, 1);
}
/* Offset 0x01: Switch MAC Address Register Bytes 0 & 1
......@@ -455,8 +433,9 @@ int mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip *chip, int index)
static int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_STATS_OP,
MV88E6XXX_G1_STATS_OP_BUSY);
int bit = __bf_shf(MV88E6XXX_G1_STATS_OP_BUSY);
return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_STATS_OP, bit, 0);
}
int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
......
......@@ -250,6 +250,8 @@
int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);
int mv88e6xxx_g1_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
bit, int val);
int mv88e6xxx_g1_wait_mask(struct mv88e6xxx_chip *chip, int reg,
u16 mask, u16 val);
......
......@@ -5,6 +5,8 @@
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2017 Savoir-faire Linux, Inc.
*/
#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
......@@ -75,8 +77,9 @@ int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip,
static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_ATU_OP,
MV88E6XXX_G1_ATU_OP_BUSY);
int bit = __bf_shf(MV88E6XXX_G1_ATU_OP_BUSY);
return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
}
static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
......
......@@ -7,6 +7,7 @@
* Copyright (c) 2017 Savoir-faire Linux, Inc.
*/
#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
......@@ -67,8 +68,9 @@ static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip,
static int mv88e6xxx_g1_vtu_op_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_VTU_OP,
MV88E6XXX_G1_VTU_OP_BUSY);
int bit = __bf_shf(MV88E6XXX_G1_VTU_OP_BUSY);
return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_VTU_OP, bit, 0);
}
static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op)
......
......@@ -36,6 +36,13 @@ int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask);
}
int mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip *chip, int reg, int
bit, int val)
{
return mv88e6xxx_wait_bit(chip, chip->info->global2_addr, reg,
bit, val);
}
/* Offset 0x00: Interrupt Source Register */
static int mv88e6xxx_g2_int_source(struct mv88e6xxx_chip *chip, u16 *src)
......@@ -178,8 +185,9 @@ int mv88e6xxx_g2_trunk_clear(struct mv88e6xxx_chip *chip)
static int mv88e6xxx_g2_irl_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_IRL_CMD,
MV88E6XXX_G2_IRL_CMD_BUSY);
int bit = __bf_shf(MV88E6XXX_G2_IRL_CMD_BUSY);
return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_IRL_CMD, bit, 0);
}
static int mv88e6xxx_g2_irl_op(struct mv88e6xxx_chip *chip, u16 op, int port,
......@@ -214,8 +222,9 @@ int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port)
static int mv88e6xxx_g2_pvt_op_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_PVT_ADDR,
MV88E6XXX_G2_PVT_ADDR_BUSY);
int bit = __bf_shf(MV88E6XXX_G2_PVT_ADDR_BUSY);
return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_PVT_ADDR, bit, 0);
}
static int mv88e6xxx_g2_pvt_op(struct mv88e6xxx_chip *chip, int src_dev,
......@@ -308,9 +317,16 @@ int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_EEPROM_CMD,
MV88E6XXX_G2_EEPROM_CMD_BUSY |
MV88E6XXX_G2_EEPROM_CMD_RUNNING);
int bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_BUSY);
int err;
err = mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
if (err)
return err;
bit = __bf_shf(MV88E6XXX_G2_EEPROM_CMD_RUNNING);
return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_EEPROM_CMD, bit, 0);
}
static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
......@@ -572,8 +588,9 @@ int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD,
MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
int bit = __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
return mv88e6xxx_g2_wait_bit(chip, MV88E6XXX_G2_SMI_PHY_CMD, bit, 0);
}
static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
......
......@@ -297,6 +297,8 @@ int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
int mv88e6xxx_g2_update(struct mv88e6xxx_chip *chip, int reg, u16 update);
int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);
int mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip *chip, int reg,
int bit, int val);
int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_g2_irl_init_all(struct mv88e6xxx_chip *chip, int port);
......@@ -386,6 +388,12 @@ static inline int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 ma
return -EOPNOTSUPP;
}
static inline int mv88e6xxx_g2_wait_bit(struct mv88e6xxx_chip *chip,
int reg, int bit, int val)
{
return -EOPNOTSUPP;
}
static inline int mv88e6352_g2_irl_init_all(struct mv88e6xxx_chip *chip,
int port)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment