cregit-Linux how code gets into the kernel

Release 4.14 net/dsa/slave.c

Directory: net/dsa
/*
 * net/dsa/slave.c - Slave device handling
 * 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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <linux/list.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/phy_fixed.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
#include <linux/mdio.h>
#include <linux/list.h>
#include <net/rtnetlink.h>
#include <net/pkt_cls.h>
#include <net/tc_act/tc_mirred.h>
#include <linux/if_bridge.h>
#include <linux/netpoll.h>

#include "dsa_priv.h"

static bool dsa_slave_dev_check(struct net_device *dev);

/* slave mii_bus handling ***************************************************/

static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg) { struct dsa_switch *ds = bus->priv; if (ds->phys_mii_mask & (1 << addr)) return ds->ops->phy_read(ds, addr, reg); return 0xffff; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek5396.36%133.33%
Florian Fainelli11.82%133.33%
Vivien Didelot11.82%133.33%
Total55100.00%3100.00%


static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val) { struct dsa_switch *ds = bus->priv; if (ds->phys_mii_mask & (1 << addr)) return ds->ops->phy_write(ds, addr, reg, val); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek5896.67%133.33%
Florian Fainelli11.67%133.33%
Vivien Didelot11.67%133.33%
Total60100.00%3100.00%


void dsa_slave_mii_bus_init(struct dsa_switch *ds) { ds->slave_mii_bus->priv = (void *)ds; ds->slave_mii_bus->name = "dsa slave smi"; ds->slave_mii_bus->read = dsa_slave_phy_read; ds->slave_mii_bus->write = dsa_slave_phy_write; snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d.%d", ds->dst->tree, ds->index); ds->slave_mii_bus->parent = ds->dev; ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek7077.78%120.00%
Vivien Didelot1112.22%120.00%
Florian Fainelli88.89%240.00%
Andrew Lunn11.11%120.00%
Total90100.00%5100.00%

/* slave device handling ****************************************************/
static int dsa_slave_get_iflink(const struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); return dsa_master_netdev(p)->ifindex; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek2480.00%133.33%
Nicolas Dichtel310.00%133.33%
Florian Fainelli310.00%133.33%
Total30100.00%3100.00%


static int dsa_slave_open(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_port *dp = p->dp; struct dsa_switch *ds = dp->ds; struct net_device *master = dsa_master_netdev(p); u8 stp_state = dp->bridge_dev ? BR_STATE_BLOCKING : BR_STATE_FORWARDING; int err; if (!(master->flags & IFF_UP)) return -ENETDOWN; if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) { err = dev_uc_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; } if (ds->ops->port_enable) { err = ds->ops->port_enable(ds, p->dp->index, p->phy); if (err) goto clear_promisc; } dsa_port_set_state_now(p->dp, stp_state); if (p->phy) phy_start(p->phy); return 0; clear_promisc: if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); clear_allmulti: if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); del_unicast: if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) dev_uc_del(master, dev->dev_addr); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek18260.87%214.29%
Florian Fainelli8528.43%428.57%
Vivien Didelot248.03%535.71%
Joe Perches41.34%17.14%
Gilad Ben-Yossef20.67%17.14%
Jiri Pirko20.67%17.14%
Total299100.00%14100.00%


static int dsa_slave_close(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = dsa_master_netdev(p); struct dsa_switch *ds = p->dp->ds; if (p->phy) phy_stop(p->phy); dev_mc_unsync(master, dev); dev_uc_unsync(master, dev); if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(master, -1); if (dev->flags & IFF_PROMISC) dev_set_promiscuity(master, -1); if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) dev_uc_del(master, dev->dev_addr); if (ds->ops->port_disable) ds->ops->port_disable(ds, p->dp->index, p->phy); dsa_port_set_state_now(p->dp, BR_STATE_DISABLED); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek9658.90%218.18%
Florian Fainelli5131.29%436.36%
Vivien Didelot127.36%327.27%
Jiri Pirko21.23%19.09%
Joe Perches21.23%19.09%
Total163100.00%11100.00%


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 = dsa_master_netdev(p); if (change & IFF_ALLMULTI) dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1); if (change & IFF_PROMISC) dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1); }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek7596.15%150.00%
Florian Fainelli33.85%150.00%
Total78100.00%2100.00%


static void dsa_slave_set_rx_mode(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = dsa_master_netdev(p); dev_mc_sync(master, dev); dev_uc_sync(master, dev); }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek4191.11%133.33%
Florian Fainelli36.67%133.33%
Jiri Pirko12.22%133.33%
Total45100.00%3100.00%


static int dsa_slave_set_mac_address(struct net_device *dev, void *a) { struct dsa_slave_priv *p = netdev_priv(dev); struct net_device *master = dsa_master_netdev(p); struct sockaddr *addr = a; int err; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; if (!(dev->flags & IFF_UP)) goto out; if (!ether_addr_equal(addr->sa_data, master->dev_addr)) { err = dev_uc_add(master, addr->sa_data); if (err < 0) return err; } if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) dev_uc_del(master, dev->dev_addr); out: ether_addr_copy(dev->dev_addr, addr->sa_data); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek9463.51%233.33%
Florian Fainelli5134.46%233.33%
Joe Perches21.35%116.67%
Jiri Pirko10.68%116.67%
Total148100.00%6100.00%

struct dsa_slave_dump_ctx { struct net_device *dev; struct sk_buff *skb; struct netlink_callback *cb; int idx; };
static int dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid, bool is_static, void *data) { struct dsa_slave_dump_ctx *dump = data; u32 portid = NETLINK_CB(dump->cb->skb).portid; u32 seq = dump->cb->nlh->nlmsg_seq; struct nlmsghdr *nlh; struct ndmsg *ndm; if (dump->idx < dump->cb->args[2]) goto skip; nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, sizeof(*ndm), NLM_F_MULTI); if (!nlh) return -EMSGSIZE; ndm = nlmsg_data(nlh); ndm->ndm_family = AF_BRIDGE; ndm->ndm_pad1 = 0; ndm->ndm_pad2 = 0; ndm->ndm_flags = NTF_SELF; ndm->ndm_type = 0; ndm->ndm_ifindex = dump->dev->ifindex; ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr)) goto nla_put_failure; if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid)) goto nla_put_failure; nlmsg_end(dump->skb, nlh); skip: dump->idx++; return 0; nla_put_failure: nlmsg_cancel(dump->skb, nlh); return -EMSGSIZE; }

Contributors

PersonTokensPropCommitsCommitProp
Arkadi Sharshevsky241100.00%1100.00%
Total241100.00%1100.00%


static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, struct net_device *filter_dev, int *idx) { struct dsa_slave_dump_ctx dump = { .dev = dev, .skb = skb, .cb = cb, .idx = *idx, }; struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_port *dp = p->dp; struct dsa_switch *ds = dp->ds; int err; if (!ds->ops->port_fdb_dump) return -EOPNOTSUPP; err = ds->ops->port_fdb_dump(ds, dp->index, dsa_slave_port_fdb_do_dump, &dump); *idx = dump.idx; return err; }

Contributors

PersonTokensPropCommitsCommitProp
Arkadi Sharshevsky131100.00%1100.00%
Total131100.00%1100.00%


static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) return phy_mii_ioctl(p->phy, ifr, cmd); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
David S. Miller3158.49%150.00%
Florian Fainelli2241.51%150.00%
Total53100.00%2100.00%


static int dsa_slave_port_attr_set(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_port *dp = p->dp; int ret; switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: ret = dsa_port_set_state(dp, attr->u.stp_state, trans); break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: ret = dsa_port_vlan_filtering(dp, attr->u.vlan_filtering, trans); break; case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans); break; default: ret = -EOPNOTSUPP; break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Vivien Didelot6756.30%758.33%
Scott Feldman3731.09%18.33%
David S. Miller86.72%18.33%
Jiri Pirko75.88%325.00%
Total119100.00%12100.00%


static int dsa_slave_port_obj_add(struct net_device *dev, const struct switchdev_obj *obj, struct switchdev_trans *trans) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_port *dp = p->dp; int err; /* For the prepare phase, ensure the full set of changes is feasable in * one go in order to signal a failure properly. If an operation is not * supported, return -EOPNOTSUPP. */ switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_port_mdb_add(dp, SWITCHDEV_OBJ_PORT_MDB(obj), trans); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_port_vlan_add(dp, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); break; default: err = -EOPNOTSUPP; break; } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Vivien Didelot8484.85%758.33%
Jiri Pirko1515.15%541.67%
Total99100.00%12100.00%


static int dsa_slave_port_obj_del(struct net_device *dev, const struct switchdev_obj *obj) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_port *dp = p->dp; int err; switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_MDB: err = dsa_port_mdb_del(dp, SWITCHDEV_OBJ_PORT_MDB(obj)); break; case SWITCHDEV_OBJ_ID_PORT_VLAN: err = dsa_port_vlan_del(dp, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; default: err = -EOPNOTSUPP; break; } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Vivien Didelot8191.01%770.00%
Jiri Pirko88.99%330.00%
Total89100.00%10100.00%


static int dsa_slave_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: attr->u.ppid.id_len = sizeof(ds->index); memcpy(&attr->u.ppid.id, &ds->index, attr->u.ppid.id_len); break; case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: attr->u.brport_flags_support = 0; break; default: return -EOPNOTSUPP; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Scott Feldman3431.19%228.57%
Lennert Buytenhek3229.36%114.29%
Florian Fainelli2724.77%114.29%
Arkadi Sharshevsky1211.01%114.29%
Vivien Didelot32.75%114.29%
Jiri Pirko10.92%114.29%
Total109100.00%7100.00%


static inline netdev_tx_t dsa_netpoll_send_skb(struct dsa_slave_priv *p, struct sk_buff *skb) { #ifdef CONFIG_NET_POLL_CONTROLLER if (p->netpoll) netpoll_send_skb(p->netpoll, skb); #else BUG(); #endif return NETDEV_TX_OK; }

Contributors

PersonTokensPropCommitsCommitProp
Florian Fainelli45100.00%1100.00%
Total45100.00%1100.00%


static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct pcpu_sw_netstats *s; struct sk_buff *nskb; s = this_cpu_ptr(p->stats64); u64_stats_update_begin(&s->syncp); s->tx_packets++; s->tx_bytes += skb->len; u64_stats_update_end(&s->syncp); /* Transmit function may have to reallocate the original SKB, * in which case it must have freed it. Only free it here on error. */ nskb = p->xmit(skb, dev); if (!nskb) { kfree_skb(skb); return NETDEV_TX_OK; } /* SKB for netpoll still need to be mangled with the protocol-specific * tag to be successfully transmitted */ if (unlikely(netpoll_tx_running(dev))) return dsa_netpoll_send_skb(p, nskb); /* Queue the SKB for transmission on the parent interface, but * do not modify its EtherType */ nskb->dev = dsa_master_netdev(p); dev_queue_xmit(nskb); return NETDEV_TX_OK; }

Contributors

PersonTokensPropCommitsCommitProp
Florian Fainelli12993.48%675.00%
Vivien Didelot85.80%112.50%
Alexander Duyck10.72%112.50%
Total138100.00%8100.00%

/* ethtool operations *******************************************************/
static int dsa_slave_get_link_ksettings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { struct dsa_slave_priv *p = netdev_priv(dev); if (!p->phy) return -EOPNOTSUPP; phy_ethtool_ksettings_get(p->phy, cmd); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek4081.63%133.33%
Yuval Shaia612.24%133.33%
Philippe Reynes36.12%133.33%
Total49100.00%3100.00%


static int dsa_slave_set_link_ksettings(struct net_device *dev, const struct ethtool_link_ksettings *cmd) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) return phy_ethtool_ksettings_set(p->phy, cmd); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek4591.84%150.00%
Philippe Reynes48.16%150.00%
Total49100.00%2100.00%


static void dsa_slave_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { strlcpy(drvinfo->driver, "dsa", sizeof(drvinfo->driver)); strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, "platform", sizeof(drvinfo->bus_info)); }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek4367.19%150.00%
Jiri Pirko2132.81%150.00%
Total64100.00%2100.00%


static int dsa_slave_get_regs_len(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; if (ds->ops->get_regs_len) return ds->ops->get_regs_len(ds, p->dp->index); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
Guenter Roeck5286.67%133.33%
Vivien Didelot813.33%266.67%
Total60100.00%3100.00%


static void dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; if (ds->ops->get_regs) ds->ops->get_regs(ds, p->dp->index, regs, _p); }

Contributors

PersonTokensPropCommitsCommitProp
Guenter Roeck6088.24%133.33%
Vivien Didelot811.76%266.67%
Total68100.00%3100.00%


static int dsa_slave_nway_reset(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) return genphy_restart_aneg(p->phy); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek41100.00%1100.00%
Total41100.00%1100.00%


static u32 dsa_slave_get_link(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); if (p->phy != NULL) { genphy_update_link(p->phy); return p->phy->link; } return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek49100.00%1100.00%
Total49100.00%1100.00%


static int dsa_slave_get_eeprom_len(struct net_device *dev) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; if (ds->cd && ds->cd->eeprom_len) return ds->cd->eeprom_len; if (ds->ops->get_eeprom_len) return ds->ops->get_eeprom_len(ds); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Guenter Roeck6184.72%120.00%
Andrew Lunn68.33%240.00%
Vivien Didelot56.94%240.00%
Total72100.00%5100.00%


static int dsa_slave_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; if (ds->ops->get_eeprom) return ds->ops->get_eeprom(ds, eeprom, data); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
Guenter Roeck6292.54%133.33%
Vivien Didelot57.46%266.67%
Total67100.00%3100.00%


static int dsa_slave_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; if (ds->ops->set_eeprom) return ds->ops->set_eeprom(ds, eeprom, data); return -EOPNOTSUPP; }

Contributors

PersonTokensPropCommitsCommitProp
Guenter Roeck6292.54%133.33%
Vivien Didelot57.46%266.67%
Total67100.00%3100.00%


static void dsa_slave_get_strings(struct net_device *dev, uint32_t stringset, uint8_t *data) { struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_switch *ds = p->dp->ds; if (stringset == ETH_SS_STATS) { int len = ETH_GSTRING_LEN; strncpy(data, "tx_packets", len); strncpy(data + len, "tx_bytes", len); strncpy(data + 2 * len, "rx_packets", len); strncpy(data + 3 * len, "rx_bytes", len); if (ds->ops->get_strings) ds->ops->get_strings(ds, p->dp->index, data + 4 * len); } }

Contributors

PersonTokensPropCommitsCommitProp
Lennert Buytenhek11993.70%133.33%
Vivien Didelot86.30%266.67%
Total127100.00%3100.00%


static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { struct dsa_switch_tree *dst = dev->dsa_ptr; struct dsa_port *cpu_dp = dsa_get_cpu_port(dst); struct dsa_switch *ds = cpu_dp->ds; s8 cpu_port = cpu_dp->index; int count = 0; if (cpu_dp->ethtool_ops.get_sset_count) { count = cpu_dp->ethtool_ops.get_sset_count(dev, ETH_SS_STATS); cpu_dp->ethtool_ops.get_ethtool_stats(dev, stats, data); } if (ds->ops->get_ethtool_stats) ds->ops->get_ethtool_stats(ds, cpu_port, data + count); }

Contributors

PersonTokensPropCommitsCommitProp
Florian Fainelli11193.28%360.00%
Vivien Didelot86.72%240.00%
Total119100.00%5100.00%


static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset) { struct dsa_switch_tree *dst = dev->dsa_ptr;