Skip to content

Commit 0620427

Browse files
hjelmelanddavem330
authored andcommitted
net: dsa: lan9303: Add fdb/mdb manipulation
Add functions for managing the lan9303 ALR (Address Logic Resolution). Implement DSA methods: port_fdb_add, port_fdb_del, port_mdb_prepare, port_mdb_add and port_mdb_del. Since the lan9303 do not offer reading specific ALR entry, the driver caches all static entries - in a flat table. Signed-off-by: Egil Hjelmeland <[email protected]> Reviewed-by: Vivien Didelot <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ab33534 commit 0620427

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

drivers/net/dsa/lan9303-core.c

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/mii.h>
2020
#include <linux/phy.h>
2121
#include <linux/if_bridge.h>
22+
#include <linux/etherdevice.h>
2223

2324
#include "lan9303.h"
2425

@@ -497,6 +498,37 @@ static int lan9303_detect_phy_setup(struct lan9303 *chip)
497498
static const int alrport_2_portmap[] = {1, 2, 4, 0, 3, 5, 6, 7 };
498499
static const int portmap_2_alrport[] = {3, 0, 1, 4, 2, 5, 6, 7 };
499500

501+
/* Return pointer to first free ALR cache entry, return NULL if none */
502+
static struct lan9303_alr_cache_entry *
503+
lan9303_alr_cache_find_free(struct lan9303 *chip)
504+
{
505+
int i;
506+
struct lan9303_alr_cache_entry *entr = chip->alr_cache;
507+
508+
for (i = 0; i < LAN9303_NUM_ALR_RECORDS; i++, entr++)
509+
if (entr->port_map == 0)
510+
return entr;
511+
512+
return NULL;
513+
}
514+
515+
/* Return pointer to ALR cache entry matching MAC address */
516+
static struct lan9303_alr_cache_entry *
517+
lan9303_alr_cache_find_mac(struct lan9303 *chip, const u8 *mac_addr)
518+
{
519+
int i;
520+
struct lan9303_alr_cache_entry *entr = chip->alr_cache;
521+
522+
BUILD_BUG_ON_MSG(sizeof(struct lan9303_alr_cache_entry) & 1,
523+
"ether_addr_equal require u16 alignment");
524+
525+
for (i = 0; i < LAN9303_NUM_ALR_RECORDS; i++, entr++)
526+
if (ether_addr_equal(entr->mac_addr, mac_addr))
527+
return entr;
528+
529+
return NULL;
530+
}
531+
500532
/* Wait a while until mask & reg == value. Otherwise return timeout. */
501533
static int lan9303_csr_reg_wait(struct lan9303 *chip, int regno,
502534
int mask, char value)
@@ -609,6 +641,73 @@ static void alr_loop_cb_fdb_port_dump(struct lan9303 *chip, u32 dat0,
609641
dump_ctx->cb(mac, 0, is_static, dump_ctx->data);
610642
}
611643

644+
/* Set a static ALR entry. Delete entry if port_map is zero */
645+
static void lan9303_alr_set_entry(struct lan9303 *chip, const u8 *mac,
646+
u8 port_map, bool stp_override)
647+
{
648+
u32 dat0, dat1, alr_port;
649+
650+
dev_dbg(chip->dev, "%s(%pM, %d)\n", __func__, mac, port_map);
651+
dat1 = LAN9303_ALR_DAT1_STATIC;
652+
if (port_map)
653+
dat1 |= LAN9303_ALR_DAT1_VALID;
654+
/* otherwise no ports: delete entry */
655+
if (stp_override)
656+
dat1 |= LAN9303_ALR_DAT1_AGE_OVERRID;
657+
658+
alr_port = portmap_2_alrport[port_map & 7];
659+
dat1 &= ~LAN9303_ALR_DAT1_PORT_MASK;
660+
dat1 |= alr_port << LAN9303_ALR_DAT1_PORT_BITOFFS;
661+
662+
dat0 = 0;
663+
dat0 |= (mac[0] << 0);
664+
dat0 |= (mac[1] << 8);
665+
dat0 |= (mac[2] << 16);
666+
dat0 |= (mac[3] << 24);
667+
668+
dat1 |= (mac[4] << 0);
669+
dat1 |= (mac[5] << 8);
670+
671+
lan9303_alr_make_entry_raw(chip, dat0, dat1);
672+
}
673+
674+
/* Add port to static ALR entry, create new static entry if needed */
675+
static int lan9303_alr_add_port(struct lan9303 *chip, const u8 *mac, int port,
676+
bool stp_override)
677+
{
678+
struct lan9303_alr_cache_entry *entr;
679+
680+
entr = lan9303_alr_cache_find_mac(chip, mac);
681+
if (!entr) { /*New entry */
682+
entr = lan9303_alr_cache_find_free(chip);
683+
if (!entr)
684+
return -ENOSPC;
685+
ether_addr_copy(entr->mac_addr, mac);
686+
}
687+
entr->port_map |= BIT(port);
688+
entr->stp_override = stp_override;
689+
lan9303_alr_set_entry(chip, mac, entr->port_map, stp_override);
690+
691+
return 0;
692+
}
693+
694+
/* Delete static port from ALR entry, delete entry if last port */
695+
static int lan9303_alr_del_port(struct lan9303 *chip, const u8 *mac, int port)
696+
{
697+
struct lan9303_alr_cache_entry *entr;
698+
699+
entr = lan9303_alr_cache_find_mac(chip, mac);
700+
if (!entr)
701+
return 0; /* no static entry found */
702+
703+
entr->port_map &= ~BIT(port);
704+
if (entr->port_map == 0) /* zero means its free again */
705+
eth_zero_addr(&entr->port_map);
706+
lan9303_alr_set_entry(chip, mac, entr->port_map, entr->stp_override);
707+
708+
return 0;
709+
}
710+
612711
static int lan9303_disable_processing_port(struct lan9303 *chip,
613712
unsigned int port)
614713
{
@@ -1065,6 +1164,32 @@ static void lan9303_port_fast_age(struct dsa_switch *ds, int port)
10651164
lan9303_alr_loop(chip, alr_loop_cb_del_port_learned, &del_ctx);
10661165
}
10671166

1167+
static int lan9303_port_fdb_add(struct dsa_switch *ds, int port,
1168+
const unsigned char *addr, u16 vid)
1169+
{
1170+
struct lan9303 *chip = ds->priv;
1171+
1172+
dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
1173+
if (vid)
1174+
return -EOPNOTSUPP;
1175+
1176+
return lan9303_alr_add_port(chip, addr, port, false);
1177+
}
1178+
1179+
static int lan9303_port_fdb_del(struct dsa_switch *ds, int port,
1180+
const unsigned char *addr, u16 vid)
1181+
1182+
{
1183+
struct lan9303 *chip = ds->priv;
1184+
1185+
dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
1186+
if (vid)
1187+
return -EOPNOTSUPP;
1188+
lan9303_alr_del_port(chip, addr, port);
1189+
1190+
return 0;
1191+
}
1192+
10681193
static int lan9303_port_fdb_dump(struct dsa_switch *ds, int port,
10691194
dsa_fdb_dump_cb_t *cb, void *data)
10701195
{
@@ -1081,6 +1206,49 @@ static int lan9303_port_fdb_dump(struct dsa_switch *ds, int port,
10811206
return 0;
10821207
}
10831208

1209+
static int lan9303_port_mdb_prepare(struct dsa_switch *ds, int port,
1210+
const struct switchdev_obj_port_mdb *mdb,
1211+
struct switchdev_trans *trans)
1212+
{
1213+
struct lan9303 *chip = ds->priv;
1214+
1215+
dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, mdb->addr,
1216+
mdb->vid);
1217+
if (mdb->vid)
1218+
return -EOPNOTSUPP;
1219+
if (lan9303_alr_cache_find_mac(chip, mdb->addr))
1220+
return 0;
1221+
if (!lan9303_alr_cache_find_free(chip))
1222+
return -ENOSPC;
1223+
1224+
return 0;
1225+
}
1226+
1227+
static void lan9303_port_mdb_add(struct dsa_switch *ds, int port,
1228+
const struct switchdev_obj_port_mdb *mdb,
1229+
struct switchdev_trans *trans)
1230+
{
1231+
struct lan9303 *chip = ds->priv;
1232+
1233+
dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, mdb->addr,
1234+
mdb->vid);
1235+
lan9303_alr_add_port(chip, mdb->addr, port, false);
1236+
}
1237+
1238+
static int lan9303_port_mdb_del(struct dsa_switch *ds, int port,
1239+
const struct switchdev_obj_port_mdb *mdb)
1240+
{
1241+
struct lan9303 *chip = ds->priv;
1242+
1243+
dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, mdb->addr,
1244+
mdb->vid);
1245+
if (mdb->vid)
1246+
return -EOPNOTSUPP;
1247+
lan9303_alr_del_port(chip, mdb->addr, port);
1248+
1249+
return 0;
1250+
}
1251+
10841252
static const struct dsa_switch_ops lan9303_switch_ops = {
10851253
.get_tag_protocol = lan9303_get_tag_protocol,
10861254
.setup = lan9303_setup,
@@ -1096,7 +1264,12 @@ static const struct dsa_switch_ops lan9303_switch_ops = {
10961264
.port_bridge_leave = lan9303_port_bridge_leave,
10971265
.port_stp_state_set = lan9303_port_stp_state_set,
10981266
.port_fast_age = lan9303_port_fast_age,
1267+
.port_fdb_add = lan9303_port_fdb_add,
1268+
.port_fdb_del = lan9303_port_fdb_del,
10991269
.port_fdb_dump = lan9303_port_fdb_dump,
1270+
.port_mdb_prepare = lan9303_port_mdb_prepare,
1271+
.port_mdb_add = lan9303_port_mdb_add,
1272+
.port_mdb_del = lan9303_port_mdb_del,
11001273
};
11011274

11021275
static int lan9303_register_switch(struct lan9303 *chip)

drivers/net/dsa/lan9303.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ struct lan9303_phy_ops {
1212
};
1313

1414
#define LAN9303_NUM_ALR_RECORDS 512
15+
struct lan9303_alr_cache_entry {
16+
u8 mac_addr[ETH_ALEN];
17+
u8 port_map; /* Bitmap of ports. Zero if unused entry */
18+
u8 stp_override; /* non zero if set ALR_DAT1_AGE_OVERRID */
19+
};
1520

1621
struct lan9303 {
1722
struct device *dev;
@@ -25,6 +30,10 @@ struct lan9303 {
2530
const struct lan9303_phy_ops *ops;
2631
bool is_bridged; /* true if port 1 and 2 are bridged */
2732
u32 swe_port_state; /* remember SWE_PORT_STATE while not bridged */
33+
/* LAN9303 do not offer reading specific ALR entry. Cache all
34+
* static entries in a flat table
35+
**/
36+
struct lan9303_alr_cache_entry alr_cache[LAN9303_NUM_ALR_RECORDS];
2837
};
2938

3039
extern const struct regmap_access_table lan9303_register_set;

0 commit comments

Comments
 (0)