net: packet: use seq_hlist_foo() helpers
[safe/jmp/linux-2.6] / net / dsa / slave.c
index 3cb331e..2175e6d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/slave.c - Slave device handling
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -10,6 +10,7 @@
 
 #include <linux/list.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/phy.h>
 #include "dsa_priv.h"
 
@@ -18,7 +19,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->valid_port_mask & (1 << addr))
+       if (ds->phys_port_mask & (1 << addr))
                return ds->drv->phy_read(ds, addr, reg);
 
        return 0xffff;
@@ -28,7 +29,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->valid_port_mask & (1 << addr))
+       if (ds->phys_port_mask & (1 << addr))
                return ds->drv->phy_write(ds, addr, reg, val);
 
        return 0;
@@ -42,25 +43,80 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
        ds->slave_mii_bus->write = dsa_slave_phy_write;
        snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x",
                        ds->master_mii_bus->id, ds->pd->sw_addr);
-       ds->slave_mii_bus->parent = &(ds->master_mii_bus->dev);
+       ds->slave_mii_bus->parent = &ds->master_mii_bus->dev;
 }
 
 
 /* slave device handling ****************************************************/
+static int dsa_slave_init(struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+
+       dev->iflink = p->parent->dst->master_netdev->ifindex;
+
+       return 0;
+}
+
 static int dsa_slave_open(struct net_device *dev)
 {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct net_device *master = p->parent->dst->master_netdev;
+       int err;
+
+       if (!(master->flags & IFF_UP))
+               return -ENETDOWN;
+
+       if (compare_ether_addr(dev->dev_addr, master->dev_addr)) {
+               err = dev_unicast_add(master, dev->dev_addr);
+               if (err < 0)
+                       goto out;
+       }
+
+       if (dev->flags & IFF_ALLMULTI) {
+               err = dev_set_allmulti(master, 1);
+               if (err < 0)
+                       goto del_unicast;
+       }
+       if (dev->flags & IFF_PROMISC) {
+               err = dev_set_promiscuity(master, 1);
+               if (err < 0)
+                       goto clear_allmulti;
+       }
+
        return 0;
+
+clear_allmulti:
+       if (dev->flags & IFF_ALLMULTI)
+               dev_set_allmulti(master, -1);
+del_unicast:
+       if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+               dev_unicast_delete(master, dev->dev_addr);
+out:
+       return err;
 }
 
 static int dsa_slave_close(struct net_device *dev)
 {
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct net_device *master = p->parent->dst->master_netdev;
+
+       dev_mc_unsync(master, dev);
+       dev_unicast_unsync(master, dev);
+       if (dev->flags & IFF_ALLMULTI)
+               dev_set_allmulti(master, -1);
+       if (dev->flags & IFF_PROMISC)
+               dev_set_promiscuity(master, -1);
+
+       if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+               dev_unicast_delete(master, dev->dev_addr);
+
        return 0;
 }
 
 static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct net_device *master = p->parent->master_netdev;
+       struct net_device *master = p->parent->dst->master_netdev;
 
        if (change & IFF_ALLMULTI)
                dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
@@ -71,15 +127,36 @@ static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
 static void dsa_slave_set_rx_mode(struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct net_device *master = p->parent->master_netdev;
+       struct net_device *master = p->parent->dst->master_netdev;
 
        dev_mc_sync(master, dev);
        dev_unicast_sync(master, dev);
 }
 
-static int dsa_slave_set_mac_address(struct net_device *dev, void *addr)
+static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
 {
-       memcpy(dev->dev_addr, addr + 2, 6);
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct net_device *master = p->parent->dst->master_netdev;
+       struct sockaddr *addr = a;
+       int err;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       if (!(dev->flags & IFF_UP))
+               goto out;
+
+       if (compare_ether_addr(addr->sa_data, master->dev_addr)) {
+               err = dev_unicast_add(master, addr->sa_data);
+               if (err < 0)
+                       return err;
+       }
+
+       if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+               dev_unicast_delete(master, dev->dev_addr);
+
+out:
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 
        return 0;
 }
@@ -218,13 +295,52 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
        .get_sset_count         = dsa_slave_get_sset_count,
 };
 
+#ifdef CONFIG_NET_DSA_TAG_DSA
+static const struct net_device_ops dsa_netdev_ops = {
+       .ndo_init               = dsa_slave_init,
+       .ndo_open               = dsa_slave_open,
+       .ndo_stop               = dsa_slave_close,
+       .ndo_start_xmit         = dsa_xmit,
+       .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
+       .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
+       .ndo_set_multicast_list = dsa_slave_set_rx_mode,
+       .ndo_set_mac_address    = dsa_slave_set_mac_address,
+       .ndo_do_ioctl           = dsa_slave_ioctl,
+};
+#endif
+#ifdef CONFIG_NET_DSA_TAG_EDSA
+static const struct net_device_ops edsa_netdev_ops = {
+       .ndo_init               = dsa_slave_init,
+       .ndo_open               = dsa_slave_open,
+       .ndo_stop               = dsa_slave_close,
+       .ndo_start_xmit         = edsa_xmit,
+       .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
+       .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
+       .ndo_set_multicast_list = dsa_slave_set_rx_mode,
+       .ndo_set_mac_address    = dsa_slave_set_mac_address,
+       .ndo_do_ioctl           = dsa_slave_ioctl,
+};
+#endif
+#ifdef CONFIG_NET_DSA_TAG_TRAILER
+static const struct net_device_ops trailer_netdev_ops = {
+       .ndo_init               = dsa_slave_init,
+       .ndo_open               = dsa_slave_open,
+       .ndo_stop               = dsa_slave_close,
+       .ndo_start_xmit         = trailer_xmit,
+       .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
+       .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
+       .ndo_set_multicast_list = dsa_slave_set_rx_mode,
+       .ndo_set_mac_address    = dsa_slave_set_mac_address,
+       .ndo_do_ioctl           = dsa_slave_ioctl,
+};
+#endif
 
 /* slave device setup *******************************************************/
 struct net_device *
 dsa_slave_create(struct dsa_switch *ds, struct device *parent,
                 int port, char *name)
 {
-       struct net_device *master = ds->master_netdev;
+       struct net_device *master = ds->dst->master_netdev;
        struct net_device *slave_dev;
        struct dsa_slave_priv *p;
        int ret;
@@ -238,22 +354,27 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        SET_ETHTOOL_OPS(slave_dev, &dsa_slave_ethtool_ops);
        memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN);
        slave_dev->tx_queue_len = 0;
-       switch (ds->tag_protocol) {
+
+       switch (ds->dst->tag_protocol) {
+#ifdef CONFIG_NET_DSA_TAG_DSA
+       case htons(ETH_P_DSA):
+               slave_dev->netdev_ops = &dsa_netdev_ops;
+               break;
+#endif
 #ifdef CONFIG_NET_DSA_TAG_EDSA
        case htons(ETH_P_EDSA):
-               slave_dev->hard_start_xmit = edsa_xmit;
+               slave_dev->netdev_ops = &edsa_netdev_ops;
+               break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_TRAILER
+       case htons(ETH_P_TRAILER):
+               slave_dev->netdev_ops = &trailer_netdev_ops;
                break;
 #endif
        default:
                BUG();
        }
-       slave_dev->open = dsa_slave_open;
-       slave_dev->stop = dsa_slave_close;
-       slave_dev->change_rx_flags = dsa_slave_change_rx_flags;
-       slave_dev->set_rx_mode = dsa_slave_set_rx_mode;
-       slave_dev->set_multicast_list = dsa_slave_set_rx_mode;
-       slave_dev->set_mac_address = dsa_slave_set_mac_address;
-       slave_dev->do_ioctl = dsa_slave_ioctl;
+
        SET_NETDEV_DEV(slave_dev, parent);
        slave_dev->vlan_features = master->vlan_features;
 
@@ -274,7 +395,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        netif_carrier_off(slave_dev);
 
        if (p->phy != NULL) {
-               phy_attach(slave_dev, p->phy->dev.bus_id,
+               phy_attach(slave_dev, dev_name(&p->phy->dev),
                           0, PHY_INTERFACE_MODE_GMII);
 
                p->phy->autoneg = AUTONEG_ENABLE;