diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx/global1_vtu.c')
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/global1_vtu.c | 370 |
1 files changed, 201 insertions, 169 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c index 48390b7b18ad..b524f27a2f0d 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -13,6 +13,7 @@ #include "chip.h" #include "global1.h" +#include "trace.h" /* Offset 0x02: VTU FID Register */ @@ -27,7 +28,7 @@ static int mv88e6xxx_g1_vtu_fid_read(struct mv88e6xxx_chip *chip, return err; entry->fid = val & MV88E6352_G1_VTU_FID_MASK; - + entry->policy = !!(val & MV88E6352_G1_VTU_FID_VID_POLICY); return 0; } @@ -36,13 +37,15 @@ static int mv88e6xxx_g1_vtu_fid_write(struct mv88e6xxx_chip *chip, { u16 val = entry->fid & MV88E6352_G1_VTU_FID_MASK; + if (entry->policy) + val |= MV88E6352_G1_VTU_FID_VID_POLICY; + return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_FID, val); } /* Offset 0x03: VTU SID Register */ -static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) +static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, u8 *sid) { u16 val; int err; @@ -51,15 +54,14 @@ static int mv88e6xxx_g1_vtu_sid_read(struct mv88e6xxx_chip *chip, if (err) return err; - entry->sid = val & MV88E6352_G1_VTU_SID_MASK; + *sid = val & MV88E6352_G1_VTU_SID_MASK; return 0; } -static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) +static int mv88e6xxx_g1_vtu_sid_write(struct mv88e6xxx_chip *chip, u8 sid) { - u16 val = entry->sid & MV88E6352_G1_VTU_SID_MASK; + u16 val = sid & MV88E6352_G1_VTU_SID_MASK; return mv88e6xxx_g1_write(chip, MV88E6352_G1_VTU_SID, val); } @@ -88,7 +90,7 @@ static int mv88e6xxx_g1_vtu_op(struct mv88e6xxx_chip *chip, u16 op) /* Offset 0x06: VTU VID Register */ static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + bool *valid, u16 *vid) { u16 val; int err; @@ -97,25 +99,28 @@ static int mv88e6xxx_g1_vtu_vid_read(struct mv88e6xxx_chip *chip, if (err) return err; - entry->vid = val & 0xfff; + if (vid) { + *vid = val & 0xfff; - if (val & MV88E6390_G1_VTU_VID_PAGE) - entry->vid |= 0x1000; + if (val & MV88E6390_G1_VTU_VID_PAGE) + *vid |= 0x1000; + } - entry->valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID); + if (valid) + *valid = !!(val & MV88E6XXX_G1_VTU_VID_VALID); return 0; } static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + bool valid, u16 vid) { - u16 val = entry->vid & 0xfff; + u16 val = vid & 0xfff; - if (entry->vid & 0x1000) + if (vid & 0x1000) val |= MV88E6390_G1_VTU_VID_PAGE; - if (entry->valid) + if (valid) val |= MV88E6XXX_G1_VTU_VID_VALID; return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_VTU_VID, val); @@ -125,11 +130,9 @@ static int mv88e6xxx_g1_vtu_vid_write(struct mv88e6xxx_chip *chip, * Offset 0x08: VTU/STU Data Register 2 * Offset 0x09: VTU/STU Data Register 3 */ - -static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) +static int mv88e6185_g1_vtu_stu_data_read(struct mv88e6xxx_chip *chip, + u16 *regs) { - u16 regs[3]; int i; /* Read all 3 VTU/STU Data registers */ @@ -142,20 +145,37 @@ static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip, return err; } - /* Extract MemberTag and PortState data */ + return 0; +} + +static int mv88e6185_g1_vtu_data_read(struct mv88e6xxx_chip *chip, + u8 *member, u8 *state) +{ + u16 regs[3]; + int err; + int i; + + err = mv88e6185_g1_vtu_stu_data_read(chip, regs); + if (err) + return err; + + /* Extract MemberTag data */ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { unsigned int member_offset = (i % 4) * 4; unsigned int state_offset = member_offset + 2; - entry->member[i] = (regs[i / 4] >> member_offset) & 0x3; - entry->state[i] = (regs[i / 4] >> state_offset) & 0x3; + if (member) + member[i] = (regs[i / 4] >> member_offset) & 0x3; + + if (state) + state[i] = (regs[i / 4] >> state_offset) & 0x3; } return 0; } static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) + u8 *member, u8 *state) { u16 regs[3] = { 0 }; int i; @@ -165,8 +185,11 @@ static int mv88e6185_g1_vtu_data_write(struct mv88e6xxx_chip *chip, unsigned int member_offset = (i % 4) * 4; unsigned int state_offset = member_offset + 2; - regs[i / 4] |= (entry->member[i] & 0x3) << member_offset; - regs[i / 4] |= (entry->state[i] & 0x3) << state_offset; + if (member) + regs[i / 4] |= (member[i] & 0x3) << member_offset; + + if (state) + regs[i / 4] |= (state[i] & 0x3) << state_offset; } /* Write all 3 VTU/STU Data registers */ @@ -234,50 +257,8 @@ static int mv88e6390_g1_vtu_data_write(struct mv88e6xxx_chip *chip, u8 *data) /* VLAN Translation Unit Operations */ -static int mv88e6xxx_g1_vtu_stu_getnext(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - int err; - - err = mv88e6xxx_g1_vtu_sid_write(chip, entry); - if (err) - return err; - - err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); - if (err) - return err; - - err = mv88e6xxx_g1_vtu_sid_read(chip, entry); - if (err) - return err; - - return mv88e6xxx_g1_vtu_vid_read(chip, entry); -} - -static int mv88e6xxx_g1_vtu_stu_get(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *vtu) -{ - struct mv88e6xxx_vtu_entry stu; - int err; - - err = mv88e6xxx_g1_vtu_sid_read(chip, vtu); - if (err) - return err; - - stu.sid = vtu->sid - 1; - - err = mv88e6xxx_g1_vtu_stu_getnext(chip, &stu); - if (err) - return err; - - if (stu.sid != vtu->sid || !stu.valid) - return -EINVAL; - - return 0; -} - -static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) +int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_vtu_entry *entry) { int err; @@ -293,7 +274,7 @@ static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, * write the VID only once, when the entry is given as invalid. */ if (!entry->valid) { - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = mv88e6xxx_g1_vtu_vid_write(chip, false, entry->vid); if (err) return err; } @@ -302,36 +283,7 @@ static int mv88e6xxx_g1_vtu_getnext(struct mv88e6xxx_chip *chip, if (err) return err; - return mv88e6xxx_g1_vtu_vid_read(chip, entry); -} - -int mv88e6250_g1_vtu_getnext(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) -{ - u16 val; - int err; - - err = mv88e6xxx_g1_vtu_getnext(chip, entry); - if (err) - return err; - - if (entry->valid) { - err = mv88e6185_g1_vtu_data_read(chip, entry); - if (err) - return err; - - /* VTU DBNum[3:0] are located in VTU Operation 3:0 - * VTU DBNum[5:4] are located in VTU Operation 9:8 - */ - err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val); - if (err) - return err; - - entry->fid = val & 0x000f; - entry->fid |= (val & 0x0300) >> 4; - } - - return 0; + return mv88e6xxx_g1_vtu_vid_read(chip, &entry->valid, &entry->vid); } int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, @@ -345,12 +297,12 @@ int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, return err; if (entry->valid) { - err = mv88e6185_g1_vtu_data_read(chip, entry); + err = mv88e6185_g1_vtu_data_read(chip, entry->member, entry->state); if (err) return err; /* VTU DBNum[3:0] are located in VTU Operation 3:0 - * VTU DBNum[7:4] are located in VTU Operation 11:8 + * VTU DBNum[7:4] ([5:4] for 6250) are located in VTU Operation 11:8 (9:8) */ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val); if (err) @@ -358,6 +310,7 @@ int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, entry->fid = val & 0x000f; entry->fid |= (val & 0x0f00) >> 4; + entry->fid &= mv88e6xxx_num_databases(chip) - 1; } return 0; @@ -374,16 +327,15 @@ int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip, return err; if (entry->valid) { - /* Fetch (and mask) VLAN PortState data from the STU */ - err = mv88e6xxx_g1_vtu_stu_get(chip, entry); + err = mv88e6185_g1_vtu_data_read(chip, entry->member, NULL); if (err) return err; - err = mv88e6185_g1_vtu_data_read(chip, entry); + err = mv88e6xxx_g1_vtu_fid_read(chip, entry); if (err) return err; - err = mv88e6xxx_g1_vtu_fid_read(chip, entry); + err = mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; } @@ -406,16 +358,11 @@ int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip, if (err) return err; - /* Fetch VLAN PortState data from the STU */ - err = mv88e6xxx_g1_vtu_stu_get(chip, entry); - if (err) - return err; - - err = mv88e6390_g1_vtu_data_read(chip, entry->state); + err = mv88e6xxx_g1_vtu_fid_read(chip, entry); if (err) return err; - err = mv88e6xxx_g1_vtu_fid_read(chip, entry); + err = mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; } @@ -423,7 +370,7 @@ int mv88e6390_g1_vtu_getnext(struct mv88e6xxx_chip *chip, return 0; } -int mv88e6250_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, +int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE; @@ -433,55 +380,62 @@ int mv88e6250_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, if (err) return err; - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; if (entry->valid) { - err = mv88e6185_g1_vtu_data_write(chip, entry); + err = mv88e6185_g1_vtu_data_write(chip, entry->member, entry->state); if (err) return err; /* VTU DBNum[3:0] are located in VTU Operation 3:0 - * VTU DBNum[5:4] are located in VTU Operation 9:8 + * VTU DBNum[7:4] are located in VTU Operation 11:8 + * + * For the 6250/6220, the latter are really [5:4] and + * 9:8, but in those cases bits 7:6 of entry->fid are + * 0 since they have num_databases = 64. */ op |= entry->fid & 0x000f; - op |= (entry->fid & 0x0030) << 4; + op |= (entry->fid & 0x00f0) << 4; } return mv88e6xxx_g1_vtu_op(chip, op); } -int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, +int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { - u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE; int err; err = mv88e6xxx_g1_vtu_op_wait(chip); if (err) return err; - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; if (entry->valid) { - err = mv88e6185_g1_vtu_data_write(chip, entry); + /* Write MemberTag data */ + err = mv88e6185_g1_vtu_data_write(chip, entry->member, NULL); if (err) return err; - /* VTU DBNum[3:0] are located in VTU Operation 3:0 - * VTU DBNum[7:4] are located in VTU Operation 11:8 - */ - op |= entry->fid & 0x000f; - op |= (entry->fid & 0x00f0) << 4; + err = mv88e6xxx_g1_vtu_fid_write(chip, entry); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); + if (err) + return err; } - return mv88e6xxx_g1_vtu_op(chip, op); + /* Load/Purge VTU entry */ + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); } -int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, +int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry) { int err; @@ -490,27 +444,21 @@ int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, if (err) return err; - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, entry->vid); if (err) return err; if (entry->valid) { - /* Write MemberTag and PortState data */ - err = mv88e6185_g1_vtu_data_write(chip, entry); - if (err) - return err; - - err = mv88e6xxx_g1_vtu_sid_write(chip, entry); + /* Write MemberTag data */ + err = mv88e6390_g1_vtu_data_write(chip, entry->member); if (err) return err; - /* Load STU entry */ - err = mv88e6xxx_g1_vtu_op(chip, - MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); + err = mv88e6xxx_g1_vtu_fid_write(chip, entry); if (err) return err; - err = mv88e6xxx_g1_vtu_fid_write(chip, entry); + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); if (err) return err; } @@ -519,50 +467,120 @@ int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); } -int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, - struct mv88e6xxx_vtu_entry *entry) +int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) { int err; + /* As part of the VTU flush, refresh FID map */ + bitmap_zero(chip->fid_bitmap, MV88E6XXX_N_FID); + err = mv88e6xxx_g1_vtu_op_wait(chip); if (err) return err; - err = mv88e6xxx_g1_vtu_vid_write(chip, entry); + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL); +} + +/* Spanning Tree Unit Operations */ + +int mv88e6xxx_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_vtu_op_wait(chip); if (err) return err; - if (entry->valid) { - /* Write PortState data */ - err = mv88e6390_g1_vtu_data_write(chip, entry->state); + /* To get the next higher active SID, the STU GetNext operation can be + * started again without setting the SID registers since it already + * contains the last SID. + * + * To save a few hardware accesses and abstract this to the caller, + * write the SID only once, when the entry is given as invalid. + */ + if (!entry->valid) { + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); if (err) return err; + } - err = mv88e6xxx_g1_vtu_sid_write(chip, entry); - if (err) - return err; + err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_GET_NEXT); + if (err) + return err; - /* Load STU entry */ - err = mv88e6xxx_g1_vtu_op(chip, - MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); - if (err) - return err; + err = mv88e6xxx_g1_vtu_vid_read(chip, &entry->valid, NULL); + if (err) + return err; - /* Write MemberTag data */ - err = mv88e6390_g1_vtu_data_write(chip, entry->member); + if (entry->valid) { + err = mv88e6xxx_g1_vtu_sid_read(chip, &entry->sid); if (err) return err; + } - err = mv88e6xxx_g1_vtu_fid_write(chip, entry); + return 0; +} + +int mv88e6352_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_stu_getnext(chip, entry); + if (err) + return err; + + if (!entry->valid) + return 0; + + return mv88e6185_g1_vtu_data_read(chip, NULL, entry->state); +} + +int mv88e6390_g1_stu_getnext(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_stu_getnext(chip, entry); + if (err) + return err; + + if (!entry->valid) + return 0; + + return mv88e6390_g1_vtu_data_read(chip, entry->state); +} + +int mv88e6352_g1_stu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) +{ + int err; + + err = mv88e6xxx_g1_vtu_op_wait(chip); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, 0); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); + if (err) + return err; + + if (entry->valid) { + err = mv88e6185_g1_vtu_data_write(chip, NULL, entry->state); if (err) return err; } - /* Load/Purge VTU entry */ - return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE); + /* Load/Purge STU entry */ + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); } -int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) +int mv88e6390_g1_stu_loadpurge(struct mv88e6xxx_chip *chip, + struct mv88e6xxx_stu_entry *entry) { int err; @@ -570,16 +588,32 @@ int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) if (err) return err; - return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_FLUSH_ALL); + err = mv88e6xxx_g1_vtu_vid_write(chip, entry->valid, 0); + if (err) + return err; + + err = mv88e6xxx_g1_vtu_sid_write(chip, entry->sid); + if (err) + return err; + + if (entry->valid) { + err = mv88e6390_g1_vtu_data_write(chip, entry->state); + if (err) + return err; + } + + /* Load/Purge STU entry */ + return mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE); } +/* VTU Violation Management */ + static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id) { struct mv88e6xxx_chip *chip = dev_id; - struct mv88e6xxx_vtu_entry entry; + u16 val, vid; int spid; int err; - u16 val; mv88e6xxx_reg_lock(chip); @@ -591,21 +625,19 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id) if (err) goto out; - err = mv88e6xxx_g1_vtu_vid_read(chip, &entry); + err = mv88e6xxx_g1_vtu_vid_read(chip, NULL, &vid); if (err) goto out; spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK; if (val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION) { - dev_err_ratelimited(chip->dev, "VTU member violation for vid %d, source port %d\n", - entry.vid, spid); + trace_mv88e6xxx_vtu_member_violation(chip->dev, spid, vid); chip->ports[spid].vtu_member_violation++; } if (val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION) { - dev_dbg_ratelimited(chip->dev, "VTU miss violation for vid %d, source port %d\n", - entry.vid, spid); + trace_mv88e6xxx_vtu_miss_violation(chip->dev, spid, vid); chip->ports[spid].vtu_miss_violation++; } |
