Skip to content

Commit ab33534

Browse files
hjelmelanddavem330
authored andcommitted
net: dsa: lan9303: Add port_fast_age and port_fdb_dump methods
Add DSA method port_fast_age as a step to STP support. Add low level functions for accessing the lan9303 ALR (Address Logic Resolution). Added DSA method port_fdb_dump Signed-off-by: Egil Hjelmeland <[email protected]> Reviewed-by: Vivien Didelot <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0d5fceb commit ab33534

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

drivers/net/dsa/lan9303-core.c

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,21 @@
124124
#define LAN9303_MAC_RX_CFG_2 0x0c01
125125
#define LAN9303_MAC_TX_CFG_2 0x0c40
126126
#define LAN9303_SWE_ALR_CMD 0x1800
127+
# define LAN9303_ALR_CMD_MAKE_ENTRY BIT(2)
128+
# define LAN9303_ALR_CMD_GET_FIRST BIT(1)
129+
# define LAN9303_ALR_CMD_GET_NEXT BIT(0)
130+
#define LAN9303_SWE_ALR_WR_DAT_0 0x1801
131+
#define LAN9303_SWE_ALR_WR_DAT_1 0x1802
132+
# define LAN9303_ALR_DAT1_VALID BIT(26)
133+
# define LAN9303_ALR_DAT1_END_OF_TABL BIT(25)
134+
# define LAN9303_ALR_DAT1_AGE_OVERRID BIT(25)
135+
# define LAN9303_ALR_DAT1_STATIC BIT(24)
136+
# define LAN9303_ALR_DAT1_PORT_BITOFFS 16
137+
# define LAN9303_ALR_DAT1_PORT_MASK (7 << LAN9303_ALR_DAT1_PORT_BITOFFS)
138+
#define LAN9303_SWE_ALR_RD_DAT_0 0x1805
139+
#define LAN9303_SWE_ALR_RD_DAT_1 0x1806
140+
#define LAN9303_SWE_ALR_CMD_STS 0x1808
141+
# define ALR_STS_MAKE_PEND BIT(0)
127142
#define LAN9303_SWE_VLAN_CMD 0x180b
128143
# define LAN9303_SWE_VLAN_CMD_RNW BIT(5)
129144
# define LAN9303_SWE_VLAN_CMD_PVIDNVLAN BIT(4)
@@ -478,6 +493,122 @@ static int lan9303_detect_phy_setup(struct lan9303 *chip)
478493
return 0;
479494
}
480495

496+
/* Map ALR-port bits to port bitmap, and back */
497+
static const int alrport_2_portmap[] = {1, 2, 4, 0, 3, 5, 6, 7 };
498+
static const int portmap_2_alrport[] = {3, 0, 1, 4, 2, 5, 6, 7 };
499+
500+
/* Wait a while until mask & reg == value. Otherwise return timeout. */
501+
static int lan9303_csr_reg_wait(struct lan9303 *chip, int regno,
502+
int mask, char value)
503+
{
504+
int i;
505+
506+
for (i = 0; i < 0x1000; i++) {
507+
u32 reg;
508+
509+
lan9303_read_switch_reg(chip, regno, &reg);
510+
if ((reg & mask) == value)
511+
return 0;
512+
usleep_range(1000, 2000);
513+
}
514+
return -ETIMEDOUT;
515+
}
516+
517+
static int lan9303_alr_make_entry_raw(struct lan9303 *chip, u32 dat0, u32 dat1)
518+
{
519+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_WR_DAT_0, dat0);
520+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_WR_DAT_1, dat1);
521+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
522+
LAN9303_ALR_CMD_MAKE_ENTRY);
523+
lan9303_csr_reg_wait(chip, LAN9303_SWE_ALR_CMD_STS, ALR_STS_MAKE_PEND,
524+
0);
525+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
526+
527+
return 0;
528+
}
529+
530+
typedef void alr_loop_cb_t(struct lan9303 *chip, u32 dat0, u32 dat1,
531+
int portmap, void *ctx);
532+
533+
static void lan9303_alr_loop(struct lan9303 *chip, alr_loop_cb_t *cb, void *ctx)
534+
{
535+
int i;
536+
537+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
538+
LAN9303_ALR_CMD_GET_FIRST);
539+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
540+
541+
for (i = 1; i < LAN9303_NUM_ALR_RECORDS; i++) {
542+
u32 dat0, dat1;
543+
int alrport, portmap;
544+
545+
lan9303_read_switch_reg(chip, LAN9303_SWE_ALR_RD_DAT_0, &dat0);
546+
lan9303_read_switch_reg(chip, LAN9303_SWE_ALR_RD_DAT_1, &dat1);
547+
if (dat1 & LAN9303_ALR_DAT1_END_OF_TABL)
548+
break;
549+
550+
alrport = (dat1 & LAN9303_ALR_DAT1_PORT_MASK) >>
551+
LAN9303_ALR_DAT1_PORT_BITOFFS;
552+
portmap = alrport_2_portmap[alrport];
553+
554+
cb(chip, dat0, dat1, portmap, ctx);
555+
556+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD,
557+
LAN9303_ALR_CMD_GET_NEXT);
558+
lan9303_write_switch_reg(chip, LAN9303_SWE_ALR_CMD, 0);
559+
}
560+
}
561+
562+
static void alr_reg_to_mac(u32 dat0, u32 dat1, u8 mac[6])
563+
{
564+
mac[0] = (dat0 >> 0) & 0xff;
565+
mac[1] = (dat0 >> 8) & 0xff;
566+
mac[2] = (dat0 >> 16) & 0xff;
567+
mac[3] = (dat0 >> 24) & 0xff;
568+
mac[4] = (dat1 >> 0) & 0xff;
569+
mac[5] = (dat1 >> 8) & 0xff;
570+
}
571+
572+
struct del_port_learned_ctx {
573+
int port;
574+
};
575+
576+
/* Clear learned (non-static) entry on given port */
577+
static void alr_loop_cb_del_port_learned(struct lan9303 *chip, u32 dat0,
578+
u32 dat1, int portmap, void *ctx)
579+
{
580+
struct del_port_learned_ctx *del_ctx = ctx;
581+
int port = del_ctx->port;
582+
583+
if (((BIT(port) & portmap) == 0) || (dat1 & LAN9303_ALR_DAT1_STATIC))
584+
return;
585+
586+
/* learned entries has only one port, we can just delete */
587+
dat1 &= ~LAN9303_ALR_DAT1_VALID; /* delete entry */
588+
lan9303_alr_make_entry_raw(chip, dat0, dat1);
589+
}
590+
591+
struct port_fdb_dump_ctx {
592+
int port;
593+
void *data;
594+
dsa_fdb_dump_cb_t *cb;
595+
};
596+
597+
static void alr_loop_cb_fdb_port_dump(struct lan9303 *chip, u32 dat0,
598+
u32 dat1, int portmap, void *ctx)
599+
{
600+
struct port_fdb_dump_ctx *dump_ctx = ctx;
601+
u8 mac[ETH_ALEN];
602+
bool is_static;
603+
604+
if ((BIT(dump_ctx->port) & portmap) == 0)
605+
return;
606+
607+
alr_reg_to_mac(dat0, dat1, mac);
608+
is_static = !!(dat1 & LAN9303_ALR_DAT1_STATIC);
609+
dump_ctx->cb(mac, 0, is_static, dump_ctx->data);
610+
}
611+
481612
static int lan9303_disable_processing_port(struct lan9303 *chip,
482613
unsigned int port)
483614
{
@@ -923,6 +1054,33 @@ static void lan9303_port_stp_state_set(struct dsa_switch *ds, int port,
9231054
/* else: touching SWE_PORT_STATE would break port separation */
9241055
}
9251056

1057+
static void lan9303_port_fast_age(struct dsa_switch *ds, int port)
1058+
{
1059+
struct lan9303 *chip = ds->priv;
1060+
struct del_port_learned_ctx del_ctx = {
1061+
.port = port,
1062+
};
1063+
1064+
dev_dbg(chip->dev, "%s(%d)\n", __func__, port);
1065+
lan9303_alr_loop(chip, alr_loop_cb_del_port_learned, &del_ctx);
1066+
}
1067+
1068+
static int lan9303_port_fdb_dump(struct dsa_switch *ds, int port,
1069+
dsa_fdb_dump_cb_t *cb, void *data)
1070+
{
1071+
struct lan9303 *chip = ds->priv;
1072+
struct port_fdb_dump_ctx dump_ctx = {
1073+
.port = port,
1074+
.data = data,
1075+
.cb = cb,
1076+
};
1077+
1078+
dev_dbg(chip->dev, "%s(%d)\n", __func__, port);
1079+
lan9303_alr_loop(chip, alr_loop_cb_fdb_port_dump, &dump_ctx);
1080+
1081+
return 0;
1082+
}
1083+
9261084
static const struct dsa_switch_ops lan9303_switch_ops = {
9271085
.get_tag_protocol = lan9303_get_tag_protocol,
9281086
.setup = lan9303_setup,
@@ -937,6 +1095,8 @@ static const struct dsa_switch_ops lan9303_switch_ops = {
9371095
.port_bridge_join = lan9303_port_bridge_join,
9381096
.port_bridge_leave = lan9303_port_bridge_leave,
9391097
.port_stp_state_set = lan9303_port_stp_state_set,
1098+
.port_fast_age = lan9303_port_fast_age,
1099+
.port_fdb_dump = lan9303_port_fdb_dump,
9401100
};
9411101

9421102
static int lan9303_register_switch(struct lan9303 *chip)

drivers/net/dsa/lan9303.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ struct lan9303_phy_ops {
1111
int regnum, u16 val);
1212
};
1313

14+
#define LAN9303_NUM_ALR_RECORDS 512
15+
1416
struct lan9303 {
1517
struct device *dev;
1618
struct regmap *regmap;

0 commit comments

Comments
 (0)