struct ar8216_priv {
struct switch_dev dev;
+ struct mii_bus *mii_bus;
struct phy_device *phy;
u32 (*read)(struct ar8216_priv *priv, int reg);
void (*write)(struct ar8216_priv *priv, int reg, u32 val);
MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"),
};
-#define to_ar8216(_dev) container_of(_dev, struct ar8216_priv, dev)
+static inline struct ar8216_priv *
+swdev_to_ar8216(struct switch_dev *swdev)
+{
+ return container_of(swdev, struct ar8216_priv, dev);
+}
static inline bool ar8xxx_has_gige(struct ar8216_priv *priv)
{
static u32
ar8216_mii_read(struct ar8216_priv *priv, int reg)
{
- struct phy_device *phy = priv->phy;
- struct mii_bus *bus = phy->bus;
+ struct mii_bus *bus = priv->mii_bus;
u16 r1, r2, page;
u16 lo, hi;
static void
ar8216_mii_write(struct ar8216_priv *priv, int reg, u32 val)
{
- struct phy_device *phy = priv->phy;
- struct mii_bus *bus = phy->bus;
+ struct mii_bus *bus = priv->mii_bus;
u16 r1, r2, r3;
u16 lo, hi;
ar8216_phy_dbg_write(struct ar8216_priv *priv, int phy_addr,
u16 dbg_addr, u16 dbg_data)
{
- struct mii_bus *bus = priv->phy->bus;
+ struct mii_bus *bus = priv->mii_bus;
mutex_lock(&bus->mdio_lock);
bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
static void
ar8216_phy_mmd_write(struct ar8216_priv *priv, int phy_addr, u16 addr, u16 data)
{
- struct mii_bus *bus = priv->phy->bus;
+ struct mii_bus *bus = priv->mii_bus;
mutex_lock(&bus->mdio_lock);
bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr);
}
static int
-ar8216_mib_capture(struct ar8216_priv *priv)
+ar8216_mib_op(struct ar8216_priv *priv, u32 op)
{
unsigned mib_func;
int ret;
else
mib_func = AR8216_REG_MIB_FUNC;
+ mutex_lock(&priv->reg_mutex);
/* Capture the hardware statistics for all ports */
- ar8216_rmw(priv, mib_func, AR8216_MIB_FUNC,
- (AR8216_MIB_FUNC_CAPTURE << AR8216_MIB_FUNC_S));
+ ar8216_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
+ mutex_unlock(&priv->reg_mutex);
/* Wait for the capturing to complete. */
ret = ar8216_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
}
static int
-ar8216_mib_flush(struct ar8216_priv *priv)
+ar8216_mib_capture(struct ar8216_priv *priv)
{
- unsigned mib_func;
- int ret;
-
- lockdep_assert_held(&priv->mib_lock);
-
- if (chip_is_ar8327(priv))
- mib_func = AR8327_REG_MIB_FUNC;
- else
- mib_func = AR8216_REG_MIB_FUNC;
-
- /* Flush hardware statistics for all ports */
- ar8216_rmw(priv, mib_func, AR8216_MIB_FUNC,
- (AR8216_MIB_FUNC_FLUSH << AR8216_MIB_FUNC_S));
-
- /* Wait for the capturing to complete. */
- ret = ar8216_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
- if (ret)
- goto out;
-
- ret = 0;
+ return ar8216_mib_op(priv, AR8216_MIB_FUNC_CAPTURE);
+}
-out:
- return ret;
+static int
+ar8216_mib_flush(struct ar8216_priv *priv)
+{
+ return ar8216_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
}
static void
u64 *mib_stats;
int i;
+ WARN_ON(port >= priv->dev.ports);
+
lockdep_assert_held(&priv->mib_lock);
if (chip_is_ar8327(priv))
return 0;
/* Initialize the PHYs */
- bus = priv->phy->bus;
+ bus = priv->mii_bus;
for (i = 0; i < 5; i++) {
mdiobus_write(bus, i, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
priv->write(priv, 0x8, newval);
/* Initialize the ports */
- bus = priv->phy->bus;
+ bus = priv->mii_bus;
for (i = 0; i < 5; i++) {
if ((i == 4) && priv->port4_phy &&
priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
case AR8327_PAD_MAC_SGMII:
t = AR8327_PAD_SGMII_EN;
+
+ /*
+ * WAR for the QUalcomm Atheros AP136 board.
+ * It seems that RGMII TX/RX delay settings needs to be
+ * applied for SGMII mode as well, The ethernet is not
+ * reliable without this.
+ */
+ t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
+ t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
+ if (cfg->rxclk_delay_en)
+ t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
+ if (cfg->txclk_delay_en)
+ t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
+
+ if (cfg->sgmii_delay_en)
+ t |= AR8327_PAD_SGMII_DELAY_EN;
+
break;
case AR8327_PAD_MAC2PHY_MII:
priv->write(priv, AR8327_REG_POWER_ON_STRIP, new_pos);
}
- bus = priv->phy->bus;
+ bus = priv->mii_bus;
for (i = 0; i < AR8327_NUM_PHYS; i++) {
ar8327_phy_fixup(priv, i);
}
static void
-ar8327_init_cpuport(struct ar8216_priv *priv)
+ar8327_config_port(struct ar8216_priv *priv, unsigned int port,
+ struct ar8327_port_cfg *cfg)
{
- struct ar8327_platform_data *pdata;
- struct ar8327_port_cfg *cfg;
u32 t;
- pdata = priv->phy->dev.platform_data;
- if (!pdata)
- return;
-
- cfg = &pdata->cpuport_cfg;
- if (!cfg->force_link) {
- priv->write(priv, AR8327_REG_PORT_STATUS(AR8216_PORT_CPU),
+ if (!cfg || !cfg->force_link) {
+ priv->write(priv, AR8327_REG_PORT_STATUS(port),
AR8216_PORT_STATUS_LINK_AUTO);
return;
}
t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0;
t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0;
t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0;
+
switch (cfg->speed) {
case AR8327_PORT_SPEED_10:
t |= AR8216_PORT_SPEED_10M;
break;
}
- priv->write(priv, AR8327_REG_PORT_STATUS(AR8216_PORT_CPU), t);
+ priv->write(priv, AR8327_REG_PORT_STATUS(port), t);
}
static void
ar8327_init_port(struct ar8216_priv *priv, int port)
{
+ struct ar8327_platform_data *pdata;
+ struct ar8327_port_cfg *cfg;
u32 t;
- if (port == AR8216_PORT_CPU) {
- ar8327_init_cpuport(priv);
- } else {
- t = AR8216_PORT_STATUS_LINK_AUTO;
- priv->write(priv, AR8327_REG_PORT_STATUS(port), t);
- }
+ pdata = priv->phy->dev.platform_data;
+
+ if (pdata && port == AR8216_PORT_CPU)
+ cfg = &pdata->port0_cfg;
+ else if (pdata && port == 6)
+ cfg = &pdata->port6_cfg;
+ else
+ cfg = NULL;
+
+ ar8327_config_port(priv, port, cfg);
priv->write(priv, AR8327_REG_PORT_HEADER(port), 0);
- priv->write(priv, AR8327_REG_PORT_VLAN0(port), 0);
+ t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
+ t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
+ priv->write(priv, AR8327_REG_PORT_VLAN0(port), t);
t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S;
priv->write(priv, AR8327_REG_PORT_VLAN1(port), t);
ar8216_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
priv->vlan = !!val->value.i;
return 0;
}
ar8216_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
val->value.i = priv->vlan;
return 0;
}
static int
ar8216_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
/* make sure no invalid PVIDs get set */
static int
ar8216_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
*vlan = priv->pvid[port];
return 0;
}
ar8216_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
priv->vlan_id[val->port_vlan] = val->value.i;
return 0;
}
ar8216_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
val->value.i = priv->vlan_id[val->port_vlan];
return 0;
}
ar8216_sw_get_port_link(struct switch_dev *dev, int port,
struct switch_port_link *link)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
ar8216_read_port_link(priv, port, link);
return 0;
static int
ar8216_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
u8 ports = priv->vlan_table[val->port_vlan];
int i;
static int
ar8216_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
u8 *vt = &priv->vlan_table[val->port_vlan];
int i, j;
static int
ar8216_sw_hw_apply(struct switch_dev *dev)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
u8 portmask[AR8X16_MAX_PORTS];
int i, j;
static int
ar8216_sw_reset_switch(struct switch_dev *dev)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
int i;
mutex_lock(&priv->reg_mutex);
const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
unsigned int len;
int ret;
const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
int port;
int ret;
const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = to_ar8216(dev);
+ struct ar8216_priv *priv = swdev_to_ar8216(dev);
const struct ar8xxx_chip *chip = priv->chip;
u64 *mib_stats;
int port;
goto unlock;
ar8216_mib_fetch_port_stat(priv, port, false);
- mutex_unlock(&priv->mib_lock);
len += snprintf(buf + len, sizeof(priv->buf) - len,
"Port %d MIB counters\n",
u16 id;
int i;
- val = ar8216_mii_read(priv, AR8216_REG_CTRL);
+ val = priv->read(priv, AR8216_REG_CTRL);
if (val == ~0)
return -ENODEV;
for (i = 0; i < AR8X16_PROBE_RETRIES; i++) {
u16 t;
- val = ar8216_mii_read(priv, AR8216_REG_CTRL);
+ val = priv->read(priv, AR8216_REG_CTRL);
if (val == ~0)
return -ENODEV;
break;
default:
printk(KERN_DEBUG
- "ar8216: Unknown Atheros device [ver=%d, rev=%d, phy_id=%04x%04x]\n",
- priv->chip_ver, priv->chip_rev,
- mdiobus_read(priv->phy->bus, priv->phy->addr, 2),
- mdiobus_read(priv->phy->bus, priv->phy->addr, 3));
+ "ar8216: Unknown Atheros device [ver=%d, rev=%d]\n",
+ priv->chip_ver, priv->chip_rev);
return -ENODEV;
}
next_port:
priv->mib_next_port++;
- if (priv->mib_next_port > priv->dev.ports)
+ if (priv->mib_next_port >= priv->dev.ports)
priv->mib_next_port = 0;
mutex_unlock(&priv->mib_lock);
return -ENOMEM;
}
+ priv->mii_bus = pdev->bus;
+ priv->read = ar8216_mii_read;
+ priv->write = ar8216_mii_write;
+
priv->phy = pdev;
ret = ar8216_id_chip(priv);
if (ret)
goto err_free_priv;
- if (pdev->addr != 0) {
- if (ar8xxx_has_gige(priv)) {
- pdev->supported |= SUPPORTED_1000baseT_Full;
- pdev->advertising |= ADVERTISED_1000baseT_Full;
- }
+ if (ar8xxx_has_gige(priv))
+ pdev->supported = SUPPORTED_1000baseT_Full;
+ else
+ pdev->supported = SUPPORTED_100baseT_Full;
+ pdev->advertising = pdev->supported;
+ if (pdev->addr != 0) {
if (chip_is_ar8316(priv)) {
/* check if we're attaching to the switch twice */
pdev = pdev->bus->phy_map[0];
return 0;
}
- if (ar8xxx_has_gige(priv))
- pdev->supported = SUPPORTED_1000baseT_Full;
- else
- pdev->supported = SUPPORTED_100baseT_Full;
- pdev->advertising = pdev->supported;
-
mutex_init(&priv->reg_mutex);
- priv->read = ar8216_mii_read;
- priv->write = ar8216_mii_write;
pdev->priv = priv;
if (ret)
goto err_free_priv;
- ret = register_switch(&priv->dev, pdev->attached_dev);
+ ret = register_switch(swdev, pdev->attached_dev);
if (ret)
goto err_cleanup_mib;
ret = priv->chip->hw_init(priv);
if (ret)
- goto err_cleanup_mib;
+ goto err_unregister_switch;
ret = ar8216_sw_reset_switch(&priv->dev);
if (ret)
- goto err_cleanup_mib;
+ goto err_unregister_switch;
dev->phy_ptr = priv;
return 0;
+err_unregister_switch:
+ unregister_switch(&priv->dev);
err_cleanup_mib:
ar8xxx_mib_cleanup(priv);
err_free_priv:
kfree(priv);
+ pdev->priv = NULL;
return ret;
}
if (priv == NULL)
return -ENOMEM;
+ priv->mii_bus = pdev->bus;
+ priv->read = ar8216_mii_read;
+ priv->write = ar8216_mii_write;
priv->phy = pdev;
ret = ar8216_id_chip(priv);
}
static void
-ar8216_remove(struct phy_device *pdev)
+ar8216_detach(struct phy_device *pdev)
{
- struct ar8216_priv *priv = pdev->priv;
struct net_device *dev = pdev->attached_dev;
- if (!priv)
+ if (!dev)
return;
+ dev->phy_ptr = NULL;
dev->priv_flags &= ~IFF_NO_IP_ALIGN;
dev->eth_mangle_rx = NULL;
dev->eth_mangle_tx = NULL;
+}
+
+static void
+ar8216_remove(struct phy_device *pdev)
+{
+ struct ar8216_priv *priv = pdev->priv;
+
+ if (!priv)
+ return;
+
+ pdev->priv = NULL;
if (pdev->addr == 0)
unregister_switch(&priv->dev);
.features = PHY_BASIC_FEATURES,
.probe = ar8216_probe,
.remove = ar8216_remove,
+ .detach = ar8216_detach,
.config_init = &ar8216_config_init,
.config_aneg = &ar8216_config_aneg,
.read_status = &ar8216_read_status,