|
|
|
@ -72,8 +72,8 @@ static int dsa_slave_get_iflink(const struct net_device *dev)
|
|
|
|
|
static int dsa_slave_open(struct net_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_port *dp = p->dp;
|
|
|
|
|
struct net_device *master = dsa_master_netdev(p);
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
if (!(master->flags & IFF_UP))
|
|
|
|
@ -122,7 +122,7 @@ 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_port *dp = p->dp;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
|
|
|
|
|
if (dev->phydev)
|
|
|
|
|
phy_stop(dev->phydev);
|
|
|
|
@ -246,14 +246,13 @@ 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_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
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;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
err = dsa_port_fdb_dump(dp, dsa_slave_port_fdb_do_dump, &dump);
|
|
|
|
@ -274,8 +273,7 @@ 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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
switch (attr->id) {
|
|
|
|
@ -301,8 +299,7 @@ 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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
/* For the prepare phase, ensure the full set of changes is feasable in
|
|
|
|
@ -329,8 +326,7 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
switch (obj->id) {
|
|
|
|
@ -351,8 +347,8 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
switch (attr->id) {
|
|
|
|
|
case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
|
|
|
|
@ -431,11 +427,11 @@ static void dsa_slave_get_drvinfo(struct net_device *dev,
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (ds->ops->get_regs_len)
|
|
|
|
|
return ds->ops->get_regs_len(ds, p->dp->index);
|
|
|
|
|
return ds->ops->get_regs_len(ds, dp->index);
|
|
|
|
|
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
}
|
|
|
|
@ -443,11 +439,11 @@ static int dsa_slave_get_regs_len(struct net_device *dev)
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (ds->ops->get_regs)
|
|
|
|
|
ds->ops->get_regs(ds, p->dp->index, regs, _p);
|
|
|
|
|
ds->ops->get_regs(ds, dp->index, regs, _p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u32 dsa_slave_get_link(struct net_device *dev)
|
|
|
|
@ -462,8 +458,8 @@ static u32 dsa_slave_get_link(struct net_device *dev)
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (ds->cd && ds->cd->eeprom_len)
|
|
|
|
|
return ds->cd->eeprom_len;
|
|
|
|
@ -477,8 +473,8 @@ static int dsa_slave_get_eeprom_len(struct net_device *dev)
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (ds->ops->get_eeprom)
|
|
|
|
|
return ds->ops->get_eeprom(ds, eeprom, data);
|
|
|
|
@ -489,8 +485,8 @@ static int dsa_slave_get_eeprom(struct net_device *dev,
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (ds->ops->set_eeprom)
|
|
|
|
|
return ds->ops->set_eeprom(ds, eeprom, data);
|
|
|
|
@ -501,8 +497,8 @@ static int dsa_slave_set_eeprom(struct net_device *dev,
|
|
|
|
|
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;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (stringset == ETH_SS_STATS) {
|
|
|
|
|
int len = ETH_GSTRING_LEN;
|
|
|
|
@ -512,7 +508,7 @@ static void dsa_slave_get_strings(struct net_device *dev,
|
|
|
|
|
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);
|
|
|
|
|
ds->ops->get_strings(ds, dp->index, data + 4 * len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -520,8 +516,9 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev,
|
|
|
|
|
struct ethtool_stats *stats,
|
|
|
|
|
uint64_t *data)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
struct pcpu_sw_netstats *s;
|
|
|
|
|
unsigned int start;
|
|
|
|
|
int i;
|
|
|
|
@ -543,13 +540,13 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev,
|
|
|
|
|
data[3] += rx_bytes;
|
|
|
|
|
}
|
|
|
|
|
if (ds->ops->get_ethtool_stats)
|
|
|
|
|
ds->ops->get_ethtool_stats(ds, p->dp->index, data + 4);
|
|
|
|
|
ds->ops->get_ethtool_stats(ds, dp->index, data + 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dsa_slave_get_sset_count(struct net_device *dev, int sset)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (sset == ETH_SS_STATS) {
|
|
|
|
|
int count;
|
|
|
|
@ -566,29 +563,29 @@ static int dsa_slave_get_sset_count(struct net_device *dev, int sset)
|
|
|
|
|
|
|
|
|
|
static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (ds->ops->get_wol)
|
|
|
|
|
ds->ops->get_wol(ds, p->dp->index, w);
|
|
|
|
|
ds->ops->get_wol(ds, dp->index, w);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
int ret = -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
if (ds->ops->set_wol)
|
|
|
|
|
ret = ds->ops->set_wol(ds, p->dp->index, w);
|
|
|
|
|
ret = ds->ops->set_wol(ds, dp->index, w);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* Port's PHY and MAC both need to be EEE capable */
|
|
|
|
@ -598,7 +595,7 @@ static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
|
|
|
|
|
if (!ds->ops->set_mac_eee)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
ret = ds->ops->set_mac_eee(ds, p->dp->index, e);
|
|
|
|
|
ret = ds->ops->set_mac_eee(ds, dp->index, e);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
@ -613,8 +610,8 @@ static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)
|
|
|
|
|
|
|
|
|
|
static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* Port's PHY and MAC both need to be EEE capable */
|
|
|
|
@ -624,7 +621,7 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)
|
|
|
|
|
if (!ds->ops->get_mac_eee)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
ret = ds->ops->get_mac_eee(ds, p->dp->index, e);
|
|
|
|
|
ret = ds->ops->get_mac_eee(ds, dp->index, e);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
@ -676,9 +673,9 @@ static void dsa_slave_poll_controller(struct net_device *dev)
|
|
|
|
|
static int dsa_slave_get_phys_port_name(struct net_device *dev,
|
|
|
|
|
char *name, size_t len)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
|
|
|
|
|
if (snprintf(name, len, "p%d", p->dp->index) >= len)
|
|
|
|
|
if (snprintf(name, len, "p%d", dp->index) >= len)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@ -701,14 +698,15 @@ static int dsa_slave_add_cls_matchall(struct net_device *dev,
|
|
|
|
|
struct tc_cls_matchall_offload *cls,
|
|
|
|
|
bool ingress)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_mall_tc_entry *mall_tc_entry;
|
|
|
|
|
__be16 protocol = cls->common.protocol;
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct net *net = dev_net(dev);
|
|
|
|
|
struct dsa_slave_priv *to_p;
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
struct net_device *to_dev;
|
|
|
|
|
const struct tc_action *a;
|
|
|
|
|
struct dsa_port *to_dp;
|
|
|
|
|
int err = -EOPNOTSUPP;
|
|
|
|
|
LIST_HEAD(actions);
|
|
|
|
|
int ifindex;
|
|
|
|
@ -741,13 +739,12 @@ static int dsa_slave_add_cls_matchall(struct net_device *dev,
|
|
|
|
|
mall_tc_entry->type = DSA_PORT_MALL_MIRROR;
|
|
|
|
|
mirror = &mall_tc_entry->mirror;
|
|
|
|
|
|
|
|
|
|
to_p = netdev_priv(to_dev);
|
|
|
|
|
to_dp = dsa_slave_to_port(to_dev);
|
|
|
|
|
|
|
|
|
|
mirror->to_local_port = to_p->dp->index;
|
|
|
|
|
mirror->to_local_port = to_dp->index;
|
|
|
|
|
mirror->ingress = ingress;
|
|
|
|
|
|
|
|
|
|
err = ds->ops->port_mirror_add(ds, p->dp->index, mirror,
|
|
|
|
|
ingress);
|
|
|
|
|
err = ds->ops->port_mirror_add(ds, dp->index, mirror, ingress);
|
|
|
|
|
if (err) {
|
|
|
|
|
kfree(mall_tc_entry);
|
|
|
|
|
return err;
|
|
|
|
@ -762,9 +759,9 @@ static int dsa_slave_add_cls_matchall(struct net_device *dev,
|
|
|
|
|
static void dsa_slave_del_cls_matchall(struct net_device *dev,
|
|
|
|
|
struct tc_cls_matchall_offload *cls)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_mall_tc_entry *mall_tc_entry;
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (!ds->ops->port_mirror_del)
|
|
|
|
|
return;
|
|
|
|
@ -777,8 +774,7 @@ static void dsa_slave_del_cls_matchall(struct net_device *dev,
|
|
|
|
|
|
|
|
|
|
switch (mall_tc_entry->type) {
|
|
|
|
|
case DSA_PORT_MALL_MIRROR:
|
|
|
|
|
ds->ops->port_mirror_del(ds, p->dp->index,
|
|
|
|
|
&mall_tc_entry->mirror);
|
|
|
|
|
ds->ops->port_mirror_del(ds, dp->index, &mall_tc_entry->mirror);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
WARN_ON(1);
|
|
|
|
@ -855,25 +851,25 @@ static void dsa_slave_get_stats64(struct net_device *dev,
|
|
|
|
|
static int dsa_slave_get_rxnfc(struct net_device *dev,
|
|
|
|
|
struct ethtool_rxnfc *nfc, u32 *rule_locs)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (!ds->ops->get_rxnfc)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
return ds->ops->get_rxnfc(ds, p->dp->index, nfc, rule_locs);
|
|
|
|
|
return ds->ops->get_rxnfc(ds, dp->index, nfc, rule_locs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dsa_slave_set_rxnfc(struct net_device *dev,
|
|
|
|
|
struct ethtool_rxnfc *nfc)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
if (!ds->ops->set_rxnfc)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
return ds->ops->set_rxnfc(ds, p->dp->index, nfc);
|
|
|
|
|
return ds->ops->set_rxnfc(ds, dp->index, nfc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct ethtool_ops dsa_slave_ethtool_ops = {
|
|
|
|
@ -933,8 +929,9 @@ static struct device_type dsa_type = {
|
|
|
|
|
|
|
|
|
|
static void dsa_slave_adjust_link(struct net_device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
unsigned int status_changed = 0;
|
|
|
|
|
|
|
|
|
|
if (p->old_link != dev->phydev->link) {
|
|
|
|
@ -953,7 +950,7 @@ static void dsa_slave_adjust_link(struct net_device *dev)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ds->ops->adjust_link && status_changed)
|
|
|
|
|
ds->ops->adjust_link(ds, p->dp->index, dev->phydev);
|
|
|
|
|
ds->ops->adjust_link(ds, dp->index, dev->phydev);
|
|
|
|
|
|
|
|
|
|
if (status_changed)
|
|
|
|
|
phy_print_status(dev->phydev);
|
|
|
|
@ -962,14 +959,14 @@ static void dsa_slave_adjust_link(struct net_device *dev)
|
|
|
|
|
static int dsa_slave_fixed_link_update(struct net_device *dev,
|
|
|
|
|
struct fixed_phy_status *status)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p;
|
|
|
|
|
struct dsa_switch *ds;
|
|
|
|
|
struct dsa_port *dp;
|
|
|
|
|
|
|
|
|
|
if (dev) {
|
|
|
|
|
p = netdev_priv(dev);
|
|
|
|
|
ds = p->dp->ds;
|
|
|
|
|
dp = dsa_slave_to_port(dev);
|
|
|
|
|
ds = dp->ds;
|
|
|
|
|
if (ds->ops->fixed_link_update)
|
|
|
|
|
ds->ops->fixed_link_update(ds, p->dp->index, status);
|
|
|
|
|
ds->ops->fixed_link_update(ds, dp->index, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@ -978,8 +975,9 @@ static int dsa_slave_fixed_link_update(struct net_device *dev,
|
|
|
|
|
/* slave device setup *******************************************************/
|
|
|
|
|
static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(slave_dev);
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(slave_dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
|
|
|
|
|
slave_dev->phydev = mdiobus_get_phy(ds->slave_mii_bus, addr);
|
|
|
|
|
if (!slave_dev->phydev) {
|
|
|
|
@ -997,14 +995,15 @@ static int dsa_slave_phy_connect(struct net_device *slave_dev, int addr)
|
|
|
|
|
|
|
|
|
|
static int dsa_slave_phy_setup(struct net_device *slave_dev)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(slave_dev);
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(slave_dev);
|
|
|
|
|
struct dsa_switch *ds = p->dp->ds;
|
|
|
|
|
struct device_node *phy_dn, *port_dn;
|
|
|
|
|
struct device_node *port_dn = dp->dn;
|
|
|
|
|
struct dsa_switch *ds = dp->ds;
|
|
|
|
|
struct device_node *phy_dn;
|
|
|
|
|
bool phy_is_fixed = false;
|
|
|
|
|
u32 phy_flags = 0;
|
|
|
|
|
int mode, ret;
|
|
|
|
|
|
|
|
|
|
port_dn = p->dp->dn;
|
|
|
|
|
mode = of_get_phy_mode(port_dn);
|
|
|
|
|
if (mode < 0)
|
|
|
|
|
mode = PHY_INTERFACE_MODE_NA;
|
|
|
|
@ -1025,7 +1024,7 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ds->ops->get_phy_flags)
|
|
|
|
|
phy_flags = ds->ops->get_phy_flags(ds, p->dp->index);
|
|
|
|
|
phy_flags = ds->ops->get_phy_flags(ds, dp->index);
|
|
|
|
|
|
|
|
|
|
if (phy_dn) {
|
|
|
|
|
int phy_id = of_mdio_parse_addr(&slave_dev->dev, phy_dn);
|
|
|
|
@ -1061,10 +1060,10 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
|
|
|
|
|
* MDIO bus instead
|
|
|
|
|
*/
|
|
|
|
|
if (!slave_dev->phydev) {
|
|
|
|
|
ret = dsa_slave_phy_connect(slave_dev, p->dp->index);
|
|
|
|
|
ret = dsa_slave_phy_connect(slave_dev, dp->index);
|
|
|
|
|
if (ret) {
|
|
|
|
|
netdev_err(slave_dev, "failed to connect to port %d: %d\n",
|
|
|
|
|
p->dp->index, ret);
|
|
|
|
|
dp->index, ret);
|
|
|
|
|
if (phy_is_fixed)
|
|
|
|
|
of_phy_deregister_fixed_link(port_dn);
|
|
|
|
|
return ret;
|
|
|
|
@ -1118,7 +1117,7 @@ static void dsa_slave_notify(struct net_device *dev, unsigned long val)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct net_device *master = dsa_master_netdev(p);
|
|
|
|
|
struct dsa_port *dp = p->dp;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
struct dsa_notifier_register_info rinfo = {
|
|
|
|
|
.switch_number = dp->ds->index,
|
|
|
|
|
.port_number = dp->index,
|
|
|
|
@ -1202,8 +1201,8 @@ int dsa_slave_create(struct dsa_port *port, const char *name)
|
|
|
|
|
|
|
|
|
|
out_phy:
|
|
|
|
|
phy_disconnect(slave_dev->phydev);
|
|
|
|
|
if (of_phy_is_fixed_link(p->dp->dn))
|
|
|
|
|
of_phy_deregister_fixed_link(p->dp->dn);
|
|
|
|
|
if (of_phy_is_fixed_link(port->dn))
|
|
|
|
|
of_phy_deregister_fixed_link(port->dn);
|
|
|
|
|
out_free:
|
|
|
|
|
free_percpu(p->stats64);
|
|
|
|
|
free_netdev(slave_dev);
|
|
|
|
@ -1213,10 +1212,9 @@ out_free:
|
|
|
|
|
|
|
|
|
|
void dsa_slave_destroy(struct net_device *slave_dev)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(slave_dev);
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(slave_dev);
|
|
|
|
|
struct device_node *port_dn;
|
|
|
|
|
|
|
|
|
|
port_dn = p->dp->dn;
|
|
|
|
|
struct device_node *port_dn = dp->dn;
|
|
|
|
|
|
|
|
|
|
netif_carrier_off(slave_dev);
|
|
|
|
|
if (slave_dev->phydev) {
|
|
|
|
@ -1239,8 +1237,7 @@ static bool dsa_slave_dev_check(struct net_device *dev)
|
|
|
|
|
static int dsa_slave_changeupper(struct net_device *dev,
|
|
|
|
|
struct netdev_notifier_changeupper_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_port *dp = p->dp;
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
int err = NOTIFY_DONE;
|
|
|
|
|
|
|
|
|
|
if (netif_is_bridge_master(info->upper_dev)) {
|
|
|
|
@ -1283,14 +1280,14 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
|
|
|
|
|
container_of(work, struct dsa_switchdev_event_work, work);
|
|
|
|
|
struct net_device *dev = switchdev_work->dev;
|
|
|
|
|
struct switchdev_notifier_fdb_info *fdb_info;
|
|
|
|
|
struct dsa_slave_priv *p = netdev_priv(dev);
|
|
|
|
|
struct dsa_port *dp = dsa_slave_to_port(dev);
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
switch (switchdev_work->event) {
|
|
|
|
|
case SWITCHDEV_FDB_ADD_TO_DEVICE:
|
|
|
|
|
fdb_info = &switchdev_work->fdb_info;
|
|
|
|
|
err = dsa_port_fdb_add(p->dp, fdb_info->addr, fdb_info->vid);
|
|
|
|
|
err = dsa_port_fdb_add(dp, fdb_info->addr, fdb_info->vid);
|
|
|
|
|
if (err) {
|
|
|
|
|
netdev_dbg(dev, "fdb add failed err=%d\n", err);
|
|
|
|
|
break;
|
|
|
|
@ -1301,7 +1298,7 @@ static void dsa_slave_switchdev_event_work(struct work_struct *work)
|
|
|
|
|
|
|
|
|
|
case SWITCHDEV_FDB_DEL_TO_DEVICE:
|
|
|
|
|
fdb_info = &switchdev_work->fdb_info;
|
|
|
|
|
err = dsa_port_fdb_del(p->dp, fdb_info->addr, fdb_info->vid);
|
|
|
|
|
err = dsa_port_fdb_del(dp, fdb_info->addr, fdb_info->vid);
|
|
|
|
|
if (err) {
|
|
|
|
|
netdev_dbg(dev, "fdb del failed err=%d\n", err);
|
|
|
|
|
dev_close(dev);
|
|
|
|
|