struct ar8216_priv {
- int (*hardstart)(struct sk_buff *skb, struct net_device *dev);
-
struct switch_dev dev;
struct phy_device *phy;
u32 (*read)(struct ar8216_priv *priv, int reg);
void (*write)(struct ar8216_priv *priv, int reg, u32 val);
+ const struct net_device_ops *ndo_old;
+ struct net_device_ops ndo;
/* all fields below are cleared on reset */
bool vlan;
- u8 vlan_id[AR8216_NUM_VLANS];
+ u16 vlan_id[AR8216_NUM_VLANS];
u8 vlan_table[AR8216_NUM_VLANS];
u8 vlan_tagged;
u16 pvid[AR8216_NUM_PORTS];
ar8216_set_pvid(struct switch_dev *dev, int port, int vlan)
{
struct ar8216_priv *priv = to_ar8216(dev);
+
+ /* make sure no invalid PVIDs get set */
+
+ if (vlan >= AR8216_NUM_VLANS)
+ return -EINVAL;
+
priv->pvid[port] = vlan;
return 0;
}
buf[1] = 0x80;
send:
- return priv->hardstart(skb, dev);
+ return priv->ndo_old->ndo_start_xmit(skb, dev);
error:
dev_kfree_skb_any(skb);
goto recv;
/* lookup port vid from local table, the switch passes an invalid vlan id */
- vlan = priv->pvid[port];
+ vlan = priv->vlan_id[priv->pvid[port]];
buf[14 + 2] &= 0xf0;
buf[14 + 2] |= vlan >> 8;
static struct switch_attr ar8216_globals[] = {
{
.type = SWITCH_TYPE_INT,
- .name = "vlan",
+ .name = "enable_vlan",
.description = "Enable VLAN mode",
.set = ar8216_set_vlan,
.get = ar8216_get_vlan,
.description = "VLAN ID",
.set = ar8216_set_vid,
.get = ar8216_get_vid,
- .max = 4095,
+ .max = 4094,
},
};
portmask[i] |= vp & ~mask;
}
- if (!priv->vlan_table[j])
- continue;
-
ar8216_vtu_op(priv,
AR8216_VTU_OP_LOAD |
(priv->vlan_id[j] << AR8216_VTU_VID_S),
} else {
egress = AR8216_OUT_STRIP_VLAN;
}
- ingress = AR8216_IN_SECURE;
+ if (priv->vlan) {
+ ingress = AR8216_IN_SECURE;
+ } else {
+ ingress = AR8216_IN_PORT_ONLY;
+ }
ar8216_rmw(priv, AR8216_REG_PORT_CTRL(i),
AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
AR8216_PORT_CTRL_LEARN |
- (i == AR8216_PORT_CPU ? AR8216_PORT_CTRL_HEADER : 0) |
+ (priv->vlan && i == AR8216_PORT_CPU ?
+ AR8216_PORT_CTRL_HEADER : 0) |
(egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
(AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
if (i == AR8216_PORT_CPU) {
priv->write(priv, AR8216_REG_PORT_STATUS(i),
AR8216_PORT_STATUS_LINK_UP |
- AR8216_PORT_STATUS_SPEED |
+ AR8216_PORT_SPEED_100M |
AR8216_PORT_STATUS_TXMAC |
AR8216_PORT_STATUS_RXMAC |
AR8216_PORT_STATUS_DUPLEX);
}
/* XXX: undocumented magic from atheros, required! */
priv->write(priv, 0x38, 0xc000050e);
+
+ ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+ AR8216_GCTRL_MTU, 1518 + 8 + 2);
+
return ar8216_hw_apply(dev);
}
dev->phy_ptr = priv;
pdev->pkt_align = 2;
- priv->hardstart = dev->hard_start_xmit;
pdev->netif_receive_skb = ar8216_netif_receive_skb;
pdev->netif_rx = ar8216_netif_rx;
- dev->hard_start_xmit = ar8216_mangle_tx;
+
+ priv->ndo_old = dev->netdev_ops;
+ memcpy(&priv->ndo, priv->ndo_old, sizeof(struct net_device_ops));
+ priv->ndo.ndo_start_xmit = ar8216_mangle_tx;
+ dev->netdev_ops = &priv->ndo;
done:
return ret;
phydev->speed = SPEED_100;
phydev->duplex = DUPLEX_FULL;
- phydev->state = PHY_UP;
+ phydev->link = 1;
/* flush the address translation unit */
if (ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0))
priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH);
+ phydev->state = PHY_RUNNING;
+ netif_carrier_on(phydev->attached_dev);
+ phydev->adjust_link(phydev->attached_dev);
+
return 0;
}
priv.phy = pdev;
val = ar8216_mii_read(&priv, AR8216_REG_CTRL);
- rev = val & 0xff;
- id = (val >> 8) & 0xff;
+ rev = val & AR8216_CTRL_REVISION;
+ id = (val & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S;
if ((id != 1) || (rev != 1))
return -ENODEV;
if (!priv)
return;
- if (priv->hardstart && dev)
- dev->hard_start_xmit = priv->hardstart;
+ if (priv->ndo_old && dev)
+ dev->netdev_ops = priv->ndo_old;
unregister_switch(&priv->dev);
kfree(priv);
}