u16 id;
int i;
+ priv->chip = UNKNOWN;
+
val = ar8216_mii_read(priv, AR8216_REG_CTRL);
if (val == ~0)
- return UNKNOWN;
+ return -ENODEV;
id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
for (i = 0; i < AR8X16_PROBE_RETRIES; i++) {
val = ar8216_mii_read(priv, AR8216_REG_CTRL);
if (val == ~0)
- return UNKNOWN;
+ return -ENODEV;
t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
if (t != id)
- return UNKNOWN;
+ return -ENODEV;
}
switch (id) {
case 0x0101:
- return AR8216;
+ priv->chip = AR8216;
+ break;
case 0x0301:
- return AR8236;
+ priv->chip = AR8236;
+ break;
case 0x1000:
case 0x1001:
- return AR8316;
+ priv->chip = AR8316;
+ break;
default:
printk(KERN_DEBUG
"ar8216: Unknown Atheros device [ver=%d, rev=%d, phy_id=%04x%04x]\n",
mdiobus_read(priv->phy->bus, priv->phy->addr, 2),
mdiobus_read(priv->phy->bus, priv->phy->addr, 3));
- return UNKNOWN;
+ return -ENODEV;
}
+
+ return 0;
}
static void
ar8216_wait_bit(struct ar8216_priv *priv, int reg, u32 mask, u32 val)
{
int timeout = 20;
+ u32 t = 0;
- while ((priv->read(priv, reg) & mask) != val) {
- if (timeout-- <= 0) {
- printk(KERN_ERR "ar8216: timeout waiting for operation to complete\n");
- return 1;
- }
+ while (1) {
+ t = priv->read(priv, reg);
+ if ((t & mask) == val)
+ return 0;
+
+ if (timeout-- <= 0)
+ break;
+
+ udelay(10);
}
- return 0;
+
+ pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n",
+ (unsigned int) reg, t, mask, val);
+ return -ETIMEDOUT;
}
static void
return 0;
}
+static void
+ar8216_init_port(struct ar8216_priv *priv, int port)
+{
+ /* Enable port learning and tx */
+ priv->write(priv, AR8216_REG_PORT_CTRL(port),
+ AR8216_PORT_CTRL_LEARN |
+ (4 << AR8216_PORT_CTRL_STATE_S));
+
+ priv->write(priv, AR8216_REG_PORT_VLAN(port), 0);
+
+ if (port == AR8216_PORT_CPU) {
+ priv->write(priv, AR8216_REG_PORT_STATUS(port),
+ AR8216_PORT_STATUS_LINK_UP |
+ ((priv->chip == AR8316) ?
+ AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) |
+ AR8216_PORT_STATUS_TXMAC |
+ AR8216_PORT_STATUS_RXMAC |
+ ((priv->chip == AR8316) ? AR8216_PORT_STATUS_RXFLOW : 0) |
+ ((priv->chip == AR8316) ? AR8216_PORT_STATUS_TXFLOW : 0) |
+ AR8216_PORT_STATUS_DUPLEX);
+ } else {
+ priv->write(priv, AR8216_REG_PORT_STATUS(port),
+ AR8216_PORT_STATUS_LINK_AUTO);
+ }
+}
+
static int
ar8216_reset_switch(struct switch_dev *dev)
{
for (i = 0; i < AR8X16_MAX_VLANS; i++) {
priv->vlan_id[i] = i;
}
- for (i = 0; i < AR8216_NUM_PORTS; i++) {
- /* Enable port learning and tx */
- priv->write(priv, AR8216_REG_PORT_CTRL(i),
- AR8216_PORT_CTRL_LEARN |
- (4 << AR8216_PORT_CTRL_STATE_S));
-
- priv->write(priv, AR8216_REG_PORT_VLAN(i), 0);
-
- /* Configure all PHYs */
- if (i == AR8216_PORT_CPU) {
- priv->write(priv, AR8216_REG_PORT_STATUS(i),
- AR8216_PORT_STATUS_LINK_UP |
- ((priv->chip == AR8316) ?
- AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) |
- AR8216_PORT_STATUS_TXMAC |
- AR8216_PORT_STATUS_RXMAC |
- ((priv->chip == AR8316) ? AR8216_PORT_STATUS_RXFLOW : 0) |
- ((priv->chip == AR8316) ? AR8216_PORT_STATUS_TXFLOW : 0) |
- AR8216_PORT_STATUS_DUPLEX);
- } else {
- priv->write(priv, AR8216_REG_PORT_STATUS(i),
- AR8216_PORT_STATUS_LINK_AUTO);
- }
- }
+
+ /* Configure all ports */
+ for (i = 0; i < AR8216_NUM_PORTS; i++)
+ ar8216_init_port(priv, i);
+
/* XXX: undocumented magic from atheros, required! */
priv->write(priv, 0x38, 0xc000050e);
priv->phy = pdev;
- priv->chip = ar8216_id_chip(priv);
+ ret = ar8216_id_chip(priv);
+ if (ret)
+ goto err_free_priv;
if (pdev->addr != 0) {
if (priv->chip == AR8316) {
swdev->vlans = AR8216_NUM_VLANS;
}
- if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) {
- kfree(priv);
- goto done;
- }
+ ret = register_switch(&priv->dev, pdev->attached_dev);
+ if (ret)
+ goto err_free_priv;
priv->init = true;
- if (priv->chip == AR8316) {
+ ret = 0;
+ if (priv->chip == AR8236)
+ ret = ar8236_hw_init(priv);
+ else if (priv->chip == AR8316)
ret = ar8316_hw_init(priv);
- if (ret) {
- kfree(priv);
- goto done;
- }
- }
- if (priv->chip == AR8236) {
- ret = ar8236_hw_init(priv);
- if (ret) {
- kfree(priv);
- goto done;
- }
- }
+ if (ret)
+ goto err_free_priv;
ret = ar8216_reset_switch(&priv->dev);
- if (ret) {
- kfree(priv);
- goto done;
- }
+ if (ret)
+ goto err_free_priv;
dev->phy_ptr = priv;
priv->init = false;
-done:
+ return 0;
+
+err_free_priv:
+ kfree(priv);
return ret;
}
/* flush the address translation unit */
mutex_lock(&priv->reg_mutex);
ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0);
-
if (!ret)
priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH);
- else
- ret = -ETIMEDOUT;
mutex_unlock(&priv->reg_mutex);
phydev->state = PHY_RUNNING;
ar8216_probe(struct phy_device *pdev)
{
struct ar8216_priv priv;
- u16 chip;
priv.phy = pdev;
- chip = ar8216_id_chip(&priv);
- if (chip == UNKNOWN)
- return -ENODEV;
-
- return 0;
+ return ar8216_id_chip(&priv);
}
static void