backport r23862
[openwrt-10.03/.git] / target / linux / generic-2.6 / files / drivers / net / phy / mvswitch.c
index f5a292a80d5611aa2929b269e568cbc950f936bf..f3a9c74e3d92657a14c410aba848b385402bd1ad 100644 (file)
@@ -38,9 +38,11 @@ MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
 MODULE_AUTHOR("Felix Fietkau");
 MODULE_LICENSE("GPL");
 
+#define MVSWITCH_MAGIC 0x88E6060
+
 struct mvswitch_priv {
-       /* the driver's tx function */
-       int (*hardstart)(struct sk_buff *skb, struct net_device *dev);
+       const struct net_device_ops *ndo_old;
+       struct net_device_ops ndo;
        struct vlan_group *grp;
        u8 vlans[16];
 };
@@ -131,7 +133,7 @@ mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
        ));
 #endif
 
-       return priv->hardstart(skb, dev);
+       return priv->ndo_old->ndo_start_xmit(skb, dev);
 
 error_expand:
        if (net_ratelimit())
@@ -245,11 +247,14 @@ mvswitch_config_init(struct phy_device *pdev)
        pdev->supported = ADVERTISED_100baseT_Full;
        pdev->advertising = ADVERTISED_100baseT_Full;
        dev->phy_ptr = priv;
-       dev->irq = PHY_POLL;
+       pdev->irq = PHY_POLL;
+#ifdef HEADER_MODE
+       dev->flags |= IFF_PROMISC;
+#endif
 
        /* initialize default vlans */
        for (i = 0; i < MV_PORTS; i++)
-               priv->vlans[(i == MV_WANPORT ? 1 : 0)] |= (1 << i);
+               priv->vlans[(i == MV_WANPORT ? 2 : 1)] |= (1 << i);
 
        /* before entering reset, disable all ports */
        for (i = 0; i < MV_PORTS; i++)
@@ -338,12 +343,15 @@ mvswitch_config_init(struct phy_device *pdev)
        );
 
        /* hook into the tx function */
+       priv->ndo_old = dev->netdev_ops;
+       memcpy(&priv->ndo, priv->ndo_old, sizeof(struct net_device_ops));
+       priv->ndo.ndo_start_xmit = mvswitch_mangle_tx;
+       priv->ndo.ndo_vlan_rx_register = mvswitch_vlan_rx_register;
+       dev->netdev_ops = &priv->ndo;
+
        pdev->pkt_align = 2;
-       priv->hardstart = dev->hard_start_xmit;
        pdev->netif_receive_skb = mvswitch_netif_receive_skb;
        pdev->netif_rx = mvswitch_netif_rx;
-       dev->hard_start_xmit = mvswitch_mangle_tx;
-       dev->vlan_rx_register = mvswitch_vlan_rx_register;
 #ifdef HEADER_MODE
        dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
 #else
@@ -358,7 +366,7 @@ mvswitch_read_status(struct phy_device *pdev)
 {
        pdev->speed = SPEED_100;
        pdev->duplex = DUPLEX_FULL;
-       pdev->state = PHY_UP;
+       pdev->link = 1;
 
        /* XXX ugly workaround: we can't force the switch
         * to gracefully handle hosts moving from one port to another,
@@ -391,47 +399,14 @@ mvswitch_remove(struct phy_device *pdev)
        struct mvswitch_priv *priv = to_mvsw(pdev);
        struct net_device *dev = pdev->attached_dev;
 
-       /* restore old xmit handler */
-       if (priv->hardstart && dev)
-               dev->hard_start_xmit = priv->hardstart;
-       dev->vlan_rx_register = NULL;
-       dev->vlan_rx_kill_vid = NULL;
+       /* restore old netdev ops */
+       if (priv->ndo_old && dev)
+               dev->netdev_ops = priv->ndo_old;
        dev->phy_ptr = NULL;
        dev->features &= ~NETIF_F_HW_VLAN_RX;
        kfree(priv);
 }
 
-static bool
-mvswitch_detect(struct mii_bus *bus, int addr)
-{
-       u16 reg;
-       int i;
-
-       /* we attach to phy id 31 to make sure that the late probe works */
-       if (addr != 31)
-               return false;
-
-       /* look for the switch on the bus */
-       reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
-       if (reg != MV_IDENT_VALUE)
-               return false;
-
-       /* 
-        * Now that we've established that the switch actually exists, let's 
-        * get rid of the competition :)
-        */
-       for (i = 0; i < 31; i++) {
-               if (!bus->phy_map[i])
-                       continue;
-
-               device_unregister(&bus->phy_map[i]->dev);
-               kfree(bus->phy_map[i]);
-               bus->phy_map[i] = NULL;
-       }
-
-       return true;
-}
-
 static int
 mvswitch_probe(struct phy_device *pdev)
 {
@@ -446,11 +421,28 @@ mvswitch_probe(struct phy_device *pdev)
        return 0;
 }
 
+static int
+mvswitch_fixup(struct phy_device *dev)
+{
+       u16 reg;
+
+       if (dev->addr != 0x10)
+               return 0;
+
+       reg = dev->bus->read(dev->bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
+       if (reg != MV_IDENT_VALUE)
+               return 0;
+
+       dev->phy_id = MVSWITCH_MAGIC;
+       return 0;
+}
+
 
 static struct phy_driver mvswitch_driver = {
        .name           = "Marvell 88E6060",
+       .phy_id         = MVSWITCH_MAGIC,
+       .phy_id_mask    = 0xffffffff,
        .features       = PHY_BASIC_FEATURES,
-       .detect         = &mvswitch_detect,
        .probe          = &mvswitch_probe,
        .remove         = &mvswitch_remove,
        .config_init    = &mvswitch_config_init,
@@ -462,6 +454,7 @@ static struct phy_driver mvswitch_driver = {
 static int __init
 mvswitch_init(void)
 {
+       phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup);
        return phy_driver_register(&mvswitch_driver);
 }