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);
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) {
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);
cfg = NULL;
ar8327_config_port(priv, port, cfg);
-
+
priv->write(priv, AR8327_REG_PORT_HEADER(port), 0);
t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
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;
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;
}
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,