Skip to content

Commit

Permalink
Merge branch 'dsa-port_fdb_dump'
Browse files Browse the repository at this point in the history
Vivien Didelot says:

====================
net: dsa: implement port_fdb_dump in drivers

Not all switch chips provide a Get Next kind of operation to dump FDB entries.
It is preferred to let the driver handle the dump operation the way it works
best for the chip. Thus, drop port_fdb_getnext and implement the port_fdb_dump
operation in DSA, which pushes the switchdev FDB dump callback down to the
drivers. mv88e6xxx is the only driver affected and is updated accordingly.

v3 -> v4: fix rejects on latest net-next

v2 -> v3: opencode switchdev_obj_dump_cb_t to avoid multiple typedef;
          use ether_addr_copy in fdb_dump

v1 -> v2: fix a few "return err" instead of "goto unlock" in mv88e6xxx.c
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Oct 22, 2015
2 parents e9829b9 + 1a49a2f commit 998eb80
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 91 deletions.
2 changes: 1 addition & 1 deletion drivers/net/dsa/mv88e6171.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
.port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
.port_fdb_add = mv88e6xxx_port_fdb_add,
.port_fdb_del = mv88e6xxx_port_fdb_del,
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
.port_fdb_dump = mv88e6xxx_port_fdb_dump,
};

MODULE_ALIAS("platform:mv88e6171");
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/dsa/mv88e6352.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
.port_fdb_prepare = mv88e6xxx_port_fdb_prepare,
.port_fdb_add = mv88e6xxx_port_fdb_add,
.port_fdb_del = mv88e6xxx_port_fdb_del,
.port_fdb_getnext = mv88e6xxx_port_fdb_getnext,
.port_fdb_dump = mv88e6xxx_port_fdb_dump,
};

MODULE_ALIAS("platform:mv88e6172");
Expand Down
132 changes: 71 additions & 61 deletions drivers/net/dsa/mv88e6xxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,13 @@ static int _mv88e6xxx_vtu_stu_data_write(struct dsa_switch *ds,
return 0;
}

static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, u16 vid,
static int _mv88e6xxx_vtu_vid_write(struct dsa_switch *ds, u16 vid)
{
return _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
vid & GLOBAL_VTU_VID_MASK);
}

static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds,
struct mv88e6xxx_vtu_stu_entry *entry)
{
struct mv88e6xxx_vtu_stu_entry next = { 0 };
Expand All @@ -1269,11 +1275,6 @@ static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds, u16 vid,
if (ret < 0)
return ret;

ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_VTU_VID,
vid & GLOBAL_VTU_VID_MASK);
if (ret < 0)
return ret;

ret = _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_VTU_GET_NEXT);
if (ret < 0)
return ret;
Expand Down Expand Up @@ -1485,7 +1486,12 @@ int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
int err;

mutex_lock(&ps->smi_mutex);
err = _mv88e6xxx_vtu_getnext(ds, vid - 1, &vlan);

err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
if (err)
goto unlock;

err = _mv88e6xxx_vtu_getnext(ds, &vlan);
if (err)
goto unlock;

Expand Down Expand Up @@ -1514,7 +1520,11 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)

mutex_lock(&ps->smi_mutex);

err = _mv88e6xxx_vtu_getnext(ds, vid - 1, &vlan);
err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
if (err)
goto unlock;

err = _mv88e6xxx_vtu_getnext(ds, &vlan);
if (err)
goto unlock;

Expand Down Expand Up @@ -1549,29 +1559,6 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
return err;
}

static int _mv88e6xxx_port_vtu_getnext(struct dsa_switch *ds, int port, u16 vid,
struct mv88e6xxx_vtu_stu_entry *entry)
{
int err;

do {
if (vid == 4095)
return -ENOENT;

err = _mv88e6xxx_vtu_getnext(ds, vid, entry);
if (err)
return err;

if (!entry->valid)
return -ENOENT;

vid = entry->vid;
} while (entry->data[port] != GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED &&
entry->data[port] != GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED);

return 0;
}

int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
unsigned long *ports, unsigned long *untagged)
{
Expand All @@ -1584,7 +1571,12 @@ int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
return -ENOENT;

mutex_lock(&ps->smi_mutex);
err = _mv88e6xxx_vtu_getnext(ds, *vid, &next);
err = _mv88e6xxx_vtu_vid_write(ds, *vid);
if (err)
goto unlock;

err = _mv88e6xxx_vtu_getnext(ds, &next);
unlock:
mutex_unlock(&ps->smi_mutex);

if (err)
Expand Down Expand Up @@ -1732,7 +1724,6 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
}

static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
const unsigned char *addr,
struct mv88e6xxx_atu_entry *entry)
{
struct mv88e6xxx_atu_entry next = { 0 };
Expand All @@ -1744,10 +1735,6 @@ static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
if (ret < 0)
return ret;

ret = _mv88e6xxx_atu_mac_write(ds, addr);
if (ret < 0)
return ret;

ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
if (ret < 0)
return ret;
Expand Down Expand Up @@ -1785,46 +1772,69 @@ static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
return 0;
}

/* get next entry for port */
int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
unsigned char *addr, u16 *vid, bool *is_static)
int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
struct switchdev_obj_port_fdb *fdb,
int (*cb)(struct switchdev_obj *obj))
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
struct mv88e6xxx_atu_entry next;
u16 fid = *vid; /* We use one FID per VLAN */
int ret;
struct mv88e6xxx_vtu_stu_entry vlan = {
.vid = GLOBAL_VTU_VID_MASK, /* all ones */
};
int err;

mutex_lock(&ps->smi_mutex);

err = _mv88e6xxx_vtu_vid_write(ds, vlan.vid);
if (err)
goto unlock;

do {
if (is_broadcast_ether_addr(addr)) {
struct mv88e6xxx_vtu_stu_entry vtu;
struct mv88e6xxx_atu_entry addr = {
.mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
};

ret = _mv88e6xxx_port_vtu_getnext(ds, port, *vid, &vtu);
if (ret < 0)
goto unlock;
err = _mv88e6xxx_vtu_getnext(ds, &vlan);
if (err)
goto unlock;

*vid = vtu.vid;
fid = vtu.fid;
}
if (!vlan.valid)
break;

ret = _mv88e6xxx_atu_getnext(ds, fid, addr, &next);
if (ret < 0)
err = _mv88e6xxx_atu_mac_write(ds, addr.mac);
if (err)
goto unlock;

ether_addr_copy(addr, next.mac);
do {
err = _mv88e6xxx_atu_getnext(ds, vlan.fid, &addr);
if (err)
goto unlock;

if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED)
continue;
} while (next.trunk || (next.portv_trunkid & BIT(port)) == 0);
if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
break;

if (!addr.trunk && addr.portv_trunkid & BIT(port)) {
bool is_static = addr.state ==
(is_multicast_ether_addr(addr.mac) ?
GLOBAL_ATU_DATA_STATE_MC_STATIC :
GLOBAL_ATU_DATA_STATE_UC_STATIC);

fdb->vid = vlan.vid;
ether_addr_copy(fdb->addr, addr.mac);
fdb->ndm_state = is_static ? NUD_NOARP :
NUD_REACHABLE;

err = cb(&fdb->obj);
if (err)
goto unlock;
}
} while (!is_broadcast_ether_addr(addr.mac));

} while (vlan.vid < GLOBAL_VTU_VID_MASK);

*is_static = next.state == (is_multicast_ether_addr(addr) ?
GLOBAL_ATU_DATA_STATE_MC_STATIC :
GLOBAL_ATU_DATA_STATE_UC_STATIC);
unlock:
mutex_unlock(&ps->smi_mutex);

return ret;
return err;
}

static void mv88e6xxx_bridge_work(struct work_struct *work)
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/dsa/mv88e6xxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,9 @@ int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
struct switchdev_trans *trans);
int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb);
int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
unsigned char *addr, u16 *vid, bool *is_static);
int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
struct switchdev_obj_port_fdb *fdb,
int (*cb)(struct switchdev_obj *obj));
int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg);
int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page,
int reg, int val);
Expand Down
7 changes: 4 additions & 3 deletions include/net/dsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ static inline u8 dsa_upstream_port(struct dsa_switch *ds)
}

struct switchdev_trans;
struct switchdev_obj;
struct switchdev_obj_port_fdb;

struct dsa_switch_driver {
Expand Down Expand Up @@ -327,9 +328,9 @@ struct dsa_switch_driver {
struct switchdev_trans *trans);
int (*port_fdb_del)(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_fdb *fdb);
int (*port_fdb_getnext)(struct dsa_switch *ds, int port,
unsigned char *addr, u16 *vid,
bool *is_static);
int (*port_fdb_dump)(struct dsa_switch *ds, int port,
struct switchdev_obj_port_fdb *fdb,
int (*cb)(struct switchdev_obj *obj));
};

void register_switch_driver(struct dsa_switch_driver *type);
Expand Down
26 changes: 3 additions & 23 deletions net/dsa/slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,31 +378,11 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev,
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->parent;
unsigned char addr[ETH_ALEN] = { 0 };
u16 vid = 0;
int ret;

if (!ds->drv->port_fdb_getnext)
return -EOPNOTSUPP;

for (;;) {
bool is_static;

ret = ds->drv->port_fdb_getnext(ds, p->port, addr, &vid,
&is_static);
if (ret < 0)
break;
if (ds->drv->port_fdb_dump)
return ds->drv->port_fdb_dump(ds, p->port, fdb, cb);

ether_addr_copy(fdb->addr, addr);
fdb->vid = vid;
fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;

ret = cb(&fdb->obj);
if (ret < 0)
break;
}

return ret == -ENOENT ? 0 : ret;
return -EOPNOTSUPP;
}

static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
Expand Down

0 comments on commit 998eb80

Please sign in to comment.