1*91da11f8SLennert Buytenhek /* 2*91da11f8SLennert Buytenhek * net/dsa/slave.c - Slave device handling 3*91da11f8SLennert Buytenhek * Copyright (c) 2008 Marvell Semiconductor 4*91da11f8SLennert Buytenhek * 5*91da11f8SLennert Buytenhek * This program is free software; you can redistribute it and/or modify 6*91da11f8SLennert Buytenhek * it under the terms of the GNU General Public License as published by 7*91da11f8SLennert Buytenhek * the Free Software Foundation; either version 2 of the License, or 8*91da11f8SLennert Buytenhek * (at your option) any later version. 9*91da11f8SLennert Buytenhek */ 10*91da11f8SLennert Buytenhek 11*91da11f8SLennert Buytenhek #include <linux/list.h> 12*91da11f8SLennert Buytenhek #include <linux/netdevice.h> 13*91da11f8SLennert Buytenhek #include <linux/phy.h> 14*91da11f8SLennert Buytenhek #include "dsa_priv.h" 15*91da11f8SLennert Buytenhek 16*91da11f8SLennert Buytenhek /* slave mii_bus handling ***************************************************/ 17*91da11f8SLennert Buytenhek static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) 18*91da11f8SLennert Buytenhek { 19*91da11f8SLennert Buytenhek struct dsa_switch *ds = bus->priv; 20*91da11f8SLennert Buytenhek 21*91da11f8SLennert Buytenhek if (ds->valid_port_mask & (1 << addr)) 22*91da11f8SLennert Buytenhek return ds->drv->phy_read(ds, addr, reg); 23*91da11f8SLennert Buytenhek 24*91da11f8SLennert Buytenhek return 0xffff; 25*91da11f8SLennert Buytenhek } 26*91da11f8SLennert Buytenhek 27*91da11f8SLennert Buytenhek static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) 28*91da11f8SLennert Buytenhek { 29*91da11f8SLennert Buytenhek struct dsa_switch *ds = bus->priv; 30*91da11f8SLennert Buytenhek 31*91da11f8SLennert Buytenhek if (ds->valid_port_mask & (1 << addr)) 32*91da11f8SLennert Buytenhek return ds->drv->phy_write(ds, addr, reg, val); 33*91da11f8SLennert Buytenhek 34*91da11f8SLennert Buytenhek return 0; 35*91da11f8SLennert Buytenhek } 36*91da11f8SLennert Buytenhek 37*91da11f8SLennert Buytenhek void dsa_slave_mii_bus_init(struct dsa_switch *ds) 38*91da11f8SLennert Buytenhek { 39*91da11f8SLennert Buytenhek ds->slave_mii_bus->priv = (void *)ds; 40*91da11f8SLennert Buytenhek ds->slave_mii_bus->name = "dsa slave smi"; 41*91da11f8SLennert Buytenhek ds->slave_mii_bus->read = dsa_slave_phy_read; 42*91da11f8SLennert Buytenhek ds->slave_mii_bus->write = dsa_slave_phy_write; 43*91da11f8SLennert Buytenhek snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x", 44*91da11f8SLennert Buytenhek ds->master_mii_bus->id, ds->pd->sw_addr); 45*91da11f8SLennert Buytenhek ds->slave_mii_bus->parent = &(ds->master_mii_bus->dev); 46*91da11f8SLennert Buytenhek } 47*91da11f8SLennert Buytenhek 48*91da11f8SLennert Buytenhek 49*91da11f8SLennert Buytenhek /* slave device handling ****************************************************/ 50*91da11f8SLennert Buytenhek static int dsa_slave_open(struct net_device *dev) 51*91da11f8SLennert Buytenhek { 52*91da11f8SLennert Buytenhek return 0; 53*91da11f8SLennert Buytenhek } 54*91da11f8SLennert Buytenhek 55*91da11f8SLennert Buytenhek static int dsa_slave_close(struct net_device *dev) 56*91da11f8SLennert Buytenhek { 57*91da11f8SLennert Buytenhek return 0; 58*91da11f8SLennert Buytenhek } 59*91da11f8SLennert Buytenhek 60*91da11f8SLennert Buytenhek static void dsa_slave_change_rx_flags(struct net_device *dev, int change) 61*91da11f8SLennert Buytenhek { 62*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 63*91da11f8SLennert Buytenhek struct net_device *master = p->parent->master_netdev; 64*91da11f8SLennert Buytenhek 65*91da11f8SLennert Buytenhek if (change & IFF_ALLMULTI) 66*91da11f8SLennert Buytenhek dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); 67*91da11f8SLennert Buytenhek if (change & IFF_PROMISC) 68*91da11f8SLennert Buytenhek dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1); 69*91da11f8SLennert Buytenhek } 70*91da11f8SLennert Buytenhek 71*91da11f8SLennert Buytenhek static void dsa_slave_set_rx_mode(struct net_device *dev) 72*91da11f8SLennert Buytenhek { 73*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 74*91da11f8SLennert Buytenhek struct net_device *master = p->parent->master_netdev; 75*91da11f8SLennert Buytenhek 76*91da11f8SLennert Buytenhek dev_mc_sync(master, dev); 77*91da11f8SLennert Buytenhek dev_unicast_sync(master, dev); 78*91da11f8SLennert Buytenhek } 79*91da11f8SLennert Buytenhek 80*91da11f8SLennert Buytenhek static int dsa_slave_set_mac_address(struct net_device *dev, void *addr) 81*91da11f8SLennert Buytenhek { 82*91da11f8SLennert Buytenhek memcpy(dev->dev_addr, addr + 2, 6); 83*91da11f8SLennert Buytenhek 84*91da11f8SLennert Buytenhek return 0; 85*91da11f8SLennert Buytenhek } 86*91da11f8SLennert Buytenhek 87*91da11f8SLennert Buytenhek static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 88*91da11f8SLennert Buytenhek { 89*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 90*91da11f8SLennert Buytenhek struct mii_ioctl_data *mii_data = if_mii(ifr); 91*91da11f8SLennert Buytenhek 92*91da11f8SLennert Buytenhek if (p->phy != NULL) 93*91da11f8SLennert Buytenhek return phy_mii_ioctl(p->phy, mii_data, cmd); 94*91da11f8SLennert Buytenhek 95*91da11f8SLennert Buytenhek return -EOPNOTSUPP; 96*91da11f8SLennert Buytenhek } 97*91da11f8SLennert Buytenhek 98*91da11f8SLennert Buytenhek 99*91da11f8SLennert Buytenhek /* ethtool operations *******************************************************/ 100*91da11f8SLennert Buytenhek static int 101*91da11f8SLennert Buytenhek dsa_slave_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 102*91da11f8SLennert Buytenhek { 103*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 104*91da11f8SLennert Buytenhek int err; 105*91da11f8SLennert Buytenhek 106*91da11f8SLennert Buytenhek err = -EOPNOTSUPP; 107*91da11f8SLennert Buytenhek if (p->phy != NULL) { 108*91da11f8SLennert Buytenhek err = phy_read_status(p->phy); 109*91da11f8SLennert Buytenhek if (err == 0) 110*91da11f8SLennert Buytenhek err = phy_ethtool_gset(p->phy, cmd); 111*91da11f8SLennert Buytenhek } 112*91da11f8SLennert Buytenhek 113*91da11f8SLennert Buytenhek return err; 114*91da11f8SLennert Buytenhek } 115*91da11f8SLennert Buytenhek 116*91da11f8SLennert Buytenhek static int 117*91da11f8SLennert Buytenhek dsa_slave_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 118*91da11f8SLennert Buytenhek { 119*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 120*91da11f8SLennert Buytenhek 121*91da11f8SLennert Buytenhek if (p->phy != NULL) 122*91da11f8SLennert Buytenhek return phy_ethtool_sset(p->phy, cmd); 123*91da11f8SLennert Buytenhek 124*91da11f8SLennert Buytenhek return -EOPNOTSUPP; 125*91da11f8SLennert Buytenhek } 126*91da11f8SLennert Buytenhek 127*91da11f8SLennert Buytenhek static void dsa_slave_get_drvinfo(struct net_device *dev, 128*91da11f8SLennert Buytenhek struct ethtool_drvinfo *drvinfo) 129*91da11f8SLennert Buytenhek { 130*91da11f8SLennert Buytenhek strncpy(drvinfo->driver, "dsa", 32); 131*91da11f8SLennert Buytenhek strncpy(drvinfo->version, dsa_driver_version, 32); 132*91da11f8SLennert Buytenhek strncpy(drvinfo->fw_version, "N/A", 32); 133*91da11f8SLennert Buytenhek strncpy(drvinfo->bus_info, "platform", 32); 134*91da11f8SLennert Buytenhek } 135*91da11f8SLennert Buytenhek 136*91da11f8SLennert Buytenhek static int dsa_slave_nway_reset(struct net_device *dev) 137*91da11f8SLennert Buytenhek { 138*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 139*91da11f8SLennert Buytenhek 140*91da11f8SLennert Buytenhek if (p->phy != NULL) 141*91da11f8SLennert Buytenhek return genphy_restart_aneg(p->phy); 142*91da11f8SLennert Buytenhek 143*91da11f8SLennert Buytenhek return -EOPNOTSUPP; 144*91da11f8SLennert Buytenhek } 145*91da11f8SLennert Buytenhek 146*91da11f8SLennert Buytenhek static u32 dsa_slave_get_link(struct net_device *dev) 147*91da11f8SLennert Buytenhek { 148*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 149*91da11f8SLennert Buytenhek 150*91da11f8SLennert Buytenhek if (p->phy != NULL) { 151*91da11f8SLennert Buytenhek genphy_update_link(p->phy); 152*91da11f8SLennert Buytenhek return p->phy->link; 153*91da11f8SLennert Buytenhek } 154*91da11f8SLennert Buytenhek 155*91da11f8SLennert Buytenhek return -EOPNOTSUPP; 156*91da11f8SLennert Buytenhek } 157*91da11f8SLennert Buytenhek 158*91da11f8SLennert Buytenhek static void dsa_slave_get_strings(struct net_device *dev, 159*91da11f8SLennert Buytenhek uint32_t stringset, uint8_t *data) 160*91da11f8SLennert Buytenhek { 161*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 162*91da11f8SLennert Buytenhek struct dsa_switch *ds = p->parent; 163*91da11f8SLennert Buytenhek 164*91da11f8SLennert Buytenhek if (stringset == ETH_SS_STATS) { 165*91da11f8SLennert Buytenhek int len = ETH_GSTRING_LEN; 166*91da11f8SLennert Buytenhek 167*91da11f8SLennert Buytenhek strncpy(data, "tx_packets", len); 168*91da11f8SLennert Buytenhek strncpy(data + len, "tx_bytes", len); 169*91da11f8SLennert Buytenhek strncpy(data + 2 * len, "rx_packets", len); 170*91da11f8SLennert Buytenhek strncpy(data + 3 * len, "rx_bytes", len); 171*91da11f8SLennert Buytenhek if (ds->drv->get_strings != NULL) 172*91da11f8SLennert Buytenhek ds->drv->get_strings(ds, p->port, data + 4 * len); 173*91da11f8SLennert Buytenhek } 174*91da11f8SLennert Buytenhek } 175*91da11f8SLennert Buytenhek 176*91da11f8SLennert Buytenhek static void dsa_slave_get_ethtool_stats(struct net_device *dev, 177*91da11f8SLennert Buytenhek struct ethtool_stats *stats, 178*91da11f8SLennert Buytenhek uint64_t *data) 179*91da11f8SLennert Buytenhek { 180*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 181*91da11f8SLennert Buytenhek struct dsa_switch *ds = p->parent; 182*91da11f8SLennert Buytenhek 183*91da11f8SLennert Buytenhek data[0] = p->dev->stats.tx_packets; 184*91da11f8SLennert Buytenhek data[1] = p->dev->stats.tx_bytes; 185*91da11f8SLennert Buytenhek data[2] = p->dev->stats.rx_packets; 186*91da11f8SLennert Buytenhek data[3] = p->dev->stats.rx_bytes; 187*91da11f8SLennert Buytenhek if (ds->drv->get_ethtool_stats != NULL) 188*91da11f8SLennert Buytenhek ds->drv->get_ethtool_stats(ds, p->port, data + 4); 189*91da11f8SLennert Buytenhek } 190*91da11f8SLennert Buytenhek 191*91da11f8SLennert Buytenhek static int dsa_slave_get_sset_count(struct net_device *dev, int sset) 192*91da11f8SLennert Buytenhek { 193*91da11f8SLennert Buytenhek struct dsa_slave_priv *p = netdev_priv(dev); 194*91da11f8SLennert Buytenhek struct dsa_switch *ds = p->parent; 195*91da11f8SLennert Buytenhek 196*91da11f8SLennert Buytenhek if (sset == ETH_SS_STATS) { 197*91da11f8SLennert Buytenhek int count; 198*91da11f8SLennert Buytenhek 199*91da11f8SLennert Buytenhek count = 4; 200*91da11f8SLennert Buytenhek if (ds->drv->get_sset_count != NULL) 201*91da11f8SLennert Buytenhek count += ds->drv->get_sset_count(ds); 202*91da11f8SLennert Buytenhek 203*91da11f8SLennert Buytenhek return count; 204*91da11f8SLennert Buytenhek } 205*91da11f8SLennert Buytenhek 206*91da11f8SLennert Buytenhek return -EOPNOTSUPP; 207*91da11f8SLennert Buytenhek } 208*91da11f8SLennert Buytenhek 209*91da11f8SLennert Buytenhek static const struct ethtool_ops dsa_slave_ethtool_ops = { 210*91da11f8SLennert Buytenhek .get_settings = dsa_slave_get_settings, 211*91da11f8SLennert Buytenhek .set_settings = dsa_slave_set_settings, 212*91da11f8SLennert Buytenhek .get_drvinfo = dsa_slave_get_drvinfo, 213*91da11f8SLennert Buytenhek .nway_reset = dsa_slave_nway_reset, 214*91da11f8SLennert Buytenhek .get_link = dsa_slave_get_link, 215*91da11f8SLennert Buytenhek .set_sg = ethtool_op_set_sg, 216*91da11f8SLennert Buytenhek .get_strings = dsa_slave_get_strings, 217*91da11f8SLennert Buytenhek .get_ethtool_stats = dsa_slave_get_ethtool_stats, 218*91da11f8SLennert Buytenhek .get_sset_count = dsa_slave_get_sset_count, 219*91da11f8SLennert Buytenhek }; 220*91da11f8SLennert Buytenhek 221*91da11f8SLennert Buytenhek 222*91da11f8SLennert Buytenhek /* slave device setup *******************************************************/ 223*91da11f8SLennert Buytenhek struct net_device * 224*91da11f8SLennert Buytenhek dsa_slave_create(struct dsa_switch *ds, struct device *parent, 225*91da11f8SLennert Buytenhek int port, char *name) 226*91da11f8SLennert Buytenhek { 227*91da11f8SLennert Buytenhek struct net_device *master = ds->master_netdev; 228*91da11f8SLennert Buytenhek struct net_device *slave_dev; 229*91da11f8SLennert Buytenhek struct dsa_slave_priv *p; 230*91da11f8SLennert Buytenhek int ret; 231*91da11f8SLennert Buytenhek 232*91da11f8SLennert Buytenhek slave_dev = alloc_netdev(sizeof(struct dsa_slave_priv), 233*91da11f8SLennert Buytenhek name, ether_setup); 234*91da11f8SLennert Buytenhek if (slave_dev == NULL) 235*91da11f8SLennert Buytenhek return slave_dev; 236*91da11f8SLennert Buytenhek 237*91da11f8SLennert Buytenhek slave_dev->features = master->vlan_features; 238*91da11f8SLennert Buytenhek SET_ETHTOOL_OPS(slave_dev, &dsa_slave_ethtool_ops); 239*91da11f8SLennert Buytenhek memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN); 240*91da11f8SLennert Buytenhek slave_dev->tx_queue_len = 0; 241*91da11f8SLennert Buytenhek switch (ds->tag_protocol) { 242*91da11f8SLennert Buytenhek #ifdef CONFIG_NET_DSA_TAG_EDSA 243*91da11f8SLennert Buytenhek case htons(ETH_P_EDSA): 244*91da11f8SLennert Buytenhek slave_dev->hard_start_xmit = edsa_xmit; 245*91da11f8SLennert Buytenhek break; 246*91da11f8SLennert Buytenhek #endif 247*91da11f8SLennert Buytenhek default: 248*91da11f8SLennert Buytenhek BUG(); 249*91da11f8SLennert Buytenhek } 250*91da11f8SLennert Buytenhek slave_dev->open = dsa_slave_open; 251*91da11f8SLennert Buytenhek slave_dev->stop = dsa_slave_close; 252*91da11f8SLennert Buytenhek slave_dev->change_rx_flags = dsa_slave_change_rx_flags; 253*91da11f8SLennert Buytenhek slave_dev->set_rx_mode = dsa_slave_set_rx_mode; 254*91da11f8SLennert Buytenhek slave_dev->set_multicast_list = dsa_slave_set_rx_mode; 255*91da11f8SLennert Buytenhek slave_dev->set_mac_address = dsa_slave_set_mac_address; 256*91da11f8SLennert Buytenhek slave_dev->do_ioctl = dsa_slave_ioctl; 257*91da11f8SLennert Buytenhek SET_NETDEV_DEV(slave_dev, parent); 258*91da11f8SLennert Buytenhek slave_dev->vlan_features = master->vlan_features; 259*91da11f8SLennert Buytenhek 260*91da11f8SLennert Buytenhek p = netdev_priv(slave_dev); 261*91da11f8SLennert Buytenhek p->dev = slave_dev; 262*91da11f8SLennert Buytenhek p->parent = ds; 263*91da11f8SLennert Buytenhek p->port = port; 264*91da11f8SLennert Buytenhek p->phy = ds->slave_mii_bus->phy_map[port]; 265*91da11f8SLennert Buytenhek 266*91da11f8SLennert Buytenhek ret = register_netdev(slave_dev); 267*91da11f8SLennert Buytenhek if (ret) { 268*91da11f8SLennert Buytenhek printk(KERN_ERR "%s: error %d registering interface %s\n", 269*91da11f8SLennert Buytenhek master->name, ret, slave_dev->name); 270*91da11f8SLennert Buytenhek free_netdev(slave_dev); 271*91da11f8SLennert Buytenhek return NULL; 272*91da11f8SLennert Buytenhek } 273*91da11f8SLennert Buytenhek 274*91da11f8SLennert Buytenhek netif_carrier_off(slave_dev); 275*91da11f8SLennert Buytenhek 276*91da11f8SLennert Buytenhek if (p->phy != NULL) { 277*91da11f8SLennert Buytenhek phy_attach(slave_dev, p->phy->dev.bus_id, 278*91da11f8SLennert Buytenhek 0, PHY_INTERFACE_MODE_GMII); 279*91da11f8SLennert Buytenhek 280*91da11f8SLennert Buytenhek p->phy->autoneg = AUTONEG_ENABLE; 281*91da11f8SLennert Buytenhek p->phy->speed = 0; 282*91da11f8SLennert Buytenhek p->phy->duplex = 0; 283*91da11f8SLennert Buytenhek p->phy->advertising = p->phy->supported | ADVERTISED_Autoneg; 284*91da11f8SLennert Buytenhek phy_start_aneg(p->phy); 285*91da11f8SLennert Buytenhek } 286*91da11f8SLennert Buytenhek 287*91da11f8SLennert Buytenhek return slave_dev; 288*91da11f8SLennert Buytenhek } 289