diff options
Diffstat (limited to 'drivers/net/ethernet/ti/cpsw_ale.c')
-rw-r--r-- | drivers/net/ethernet/ti/cpsw_ale.c | 421 |
1 files changed, 349 insertions, 72 deletions
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 9ad872bfae3a..a6a455c32628 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -32,6 +32,7 @@ #define ALE_STATUS 0x04 #define ALE_CONTROL 0x08 #define ALE_PRESCALE 0x10 +#define ALE_AGING_TIMER 0x14 #define ALE_UNKNOWNVLAN 0x18 #define ALE_TABLE_CONTROL 0x20 #define ALE_TABLE 0x34 @@ -46,6 +47,46 @@ #define AM65_CPSW_ALE_THREAD_DEF_REG 0x134 +/* ALE_AGING_TIMER */ +#define ALE_AGING_TIMER_MASK GENMASK(23, 0) + +/** + * struct ale_entry_fld - The ALE tbl entry field description + * @start_bit: field start bit + * @num_bits: field bit length + * @flags: field flags + */ +struct ale_entry_fld { + u8 start_bit; + u8 num_bits; + u8 flags; +}; + +enum { + CPSW_ALE_F_STATUS_REG = BIT(0), /* Status register present */ + CPSW_ALE_F_HW_AUTOAGING = BIT(1), /* HW auto aging */ + + CPSW_ALE_F_COUNT +}; + +/** + * struct ale_dev_id - The ALE version/SoC specific configuration + * @dev_id: ALE version/SoC id + * @features: features supported by ALE + * @tbl_entries: number of ALE entries + * @major_ver_mask: mask of ALE Major Version Value in ALE_IDVER reg. + * @nu_switch_ale: NU Switch ALE + * @vlan_entry_tbl: ALE vlan entry fields description tbl + */ +struct cpsw_ale_dev_id { + const char *dev_id; + u32 features; + u32 tbl_entries; + u32 major_ver_mask; + bool nu_switch_ale; + const struct ale_entry_fld *vlan_entry_tbl; +}; + #define ALE_TABLE_WRITE BIT(31) #define ALE_TYPE_FREE 0 @@ -60,7 +101,6 @@ #define ALE_TABLE_SIZE_MULTIPLIER 1024 #define ALE_STATUS_SIZE_MASK 0x1f -#define ALE_TABLE_SIZE_DEFAULT 64 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) { @@ -106,6 +146,59 @@ static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value, \ cpsw_ale_set_field(ale_entry, start, bits, value); \ } +enum { + ALE_ENT_VID_MEMBER_LIST = 0, + ALE_ENT_VID_UNREG_MCAST_MSK, + ALE_ENT_VID_REG_MCAST_MSK, + ALE_ENT_VID_FORCE_UNTAGGED_MSK, + ALE_ENT_VID_UNREG_MCAST_IDX, + ALE_ENT_VID_REG_MCAST_IDX, + ALE_ENT_VID_LAST, +}; + +#define ALE_FLD_ALLOWED BIT(0) +#define ALE_FLD_SIZE_PORT_MASK_BITS BIT(1) +#define ALE_FLD_SIZE_PORT_NUM_BITS BIT(2) + +#define ALE_ENTRY_FLD(id, start, bits) \ +[id] = { \ + .start_bit = start, \ + .num_bits = bits, \ + .flags = ALE_FLD_ALLOWED, \ +} + +#define ALE_ENTRY_FLD_DYN_MSK_SIZE(id, start) \ +[id] = { \ + .start_bit = start, \ + .num_bits = 0, \ + .flags = ALE_FLD_ALLOWED | \ + ALE_FLD_SIZE_PORT_MASK_BITS, \ +} + +/* dm814x, am3/am4/am5, k2hk */ +static const struct ale_entry_fld vlan_entry_cpsw[ALE_ENT_VID_LAST] = { + ALE_ENTRY_FLD(ALE_ENT_VID_MEMBER_LIST, 0, 3), + ALE_ENTRY_FLD(ALE_ENT_VID_UNREG_MCAST_MSK, 8, 3), + ALE_ENTRY_FLD(ALE_ENT_VID_REG_MCAST_MSK, 16, 3), + ALE_ENTRY_FLD(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24, 3), +}; + +/* k2e/k2l, k3 am65/j721e cpsw2g */ +static const struct ale_entry_fld vlan_entry_nu[ALE_ENT_VID_LAST] = { + ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_MEMBER_LIST, 0), + ALE_ENTRY_FLD(ALE_ENT_VID_UNREG_MCAST_IDX, 20, 3), + ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24), + ALE_ENTRY_FLD(ALE_ENT_VID_REG_MCAST_IDX, 44, 3), +}; + +/* K3 j721e/j7200 cpsw9g/5g, am64x cpsw3g */ +static const struct ale_entry_fld vlan_entry_k3_cpswxg[] = { + ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_MEMBER_LIST, 0), + ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_UNREG_MCAST_MSK, 12), + ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_FORCE_UNTAGGED_MSK, 24), + ALE_ENTRY_FLD_DYN_MSK_SIZE(ALE_ENT_VID_REG_MCAST_MSK, 36), +}; + DEFINE_ALE_FIELD(entry_type, 60, 2) DEFINE_ALE_FIELD(vlan_id, 48, 12) DEFINE_ALE_FIELD(mcast_state, 62, 2) @@ -115,17 +208,76 @@ DEFINE_ALE_FIELD(ucast_type, 62, 2) DEFINE_ALE_FIELD1(port_num, 66) DEFINE_ALE_FIELD(blocked, 65, 1) DEFINE_ALE_FIELD(secure, 64, 1) -DEFINE_ALE_FIELD1(vlan_untag_force, 24) -DEFINE_ALE_FIELD1(vlan_reg_mcast, 16) -DEFINE_ALE_FIELD1(vlan_unreg_mcast, 8) -DEFINE_ALE_FIELD1(vlan_member_list, 0) DEFINE_ALE_FIELD(mcast, 40, 1) -/* ALE NetCP nu switch specific */ -DEFINE_ALE_FIELD(vlan_unreg_mcast_idx, 20, 3) -DEFINE_ALE_FIELD(vlan_reg_mcast_idx, 44, 3) #define NU_VLAN_UNREG_MCAST_IDX 1 +static int cpsw_ale_entry_get_fld(struct cpsw_ale *ale, + u32 *ale_entry, + const struct ale_entry_fld *entry_tbl, + int fld_id) +{ + const struct ale_entry_fld *entry_fld; + u32 bits; + + if (!ale || !ale_entry) + return -EINVAL; + + entry_fld = &entry_tbl[fld_id]; + if (!(entry_fld->flags & ALE_FLD_ALLOWED)) { + dev_err(ale->params.dev, "get: wrong ale fld id %d\n", fld_id); + return -ENOENT; + } + + bits = entry_fld->num_bits; + if (entry_fld->flags & ALE_FLD_SIZE_PORT_MASK_BITS) + bits = ale->port_mask_bits; + + return cpsw_ale_get_field(ale_entry, entry_fld->start_bit, bits); +} + +static void cpsw_ale_entry_set_fld(struct cpsw_ale *ale, + u32 *ale_entry, + const struct ale_entry_fld *entry_tbl, + int fld_id, + u32 value) +{ + const struct ale_entry_fld *entry_fld; + u32 bits; + + if (!ale || !ale_entry) + return; + + entry_fld = &entry_tbl[fld_id]; + if (!(entry_fld->flags & ALE_FLD_ALLOWED)) { + dev_err(ale->params.dev, "set: wrong ale fld id %d\n", fld_id); + return; + } + + bits = entry_fld->num_bits; + if (entry_fld->flags & ALE_FLD_SIZE_PORT_MASK_BITS) + bits = ale->port_mask_bits; + + cpsw_ale_set_field(ale_entry, entry_fld->start_bit, bits, value); +} + +static int cpsw_ale_vlan_get_fld(struct cpsw_ale *ale, + u32 *ale_entry, + int fld_id) +{ + return cpsw_ale_entry_get_fld(ale, ale_entry, + ale->vlan_entry_tbl, fld_id); +} + +static void cpsw_ale_vlan_set_fld(struct cpsw_ale *ale, + u32 *ale_entry, + int fld_id, + u32 value) +{ + cpsw_ale_entry_set_fld(ale, ale_entry, + ale->vlan_entry_tbl, fld_id, value); +} + /* The MAC address field in the ALE entry cannot be macroized as above */ static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr) { @@ -420,19 +572,22 @@ static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry, int idx; /* Set VLAN registered multicast flood mask */ - idx = cpsw_ale_get_vlan_reg_mcast_idx(ale_entry); + idx = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_REG_MCAST_IDX); writel(reg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx)); /* Set VLAN unregistered multicast flood mask */ - idx = cpsw_ale_get_vlan_unreg_mcast_idx(ale_entry); + idx = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_IDX); writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx)); } static void cpsw_ale_set_vlan_untag(struct cpsw_ale *ale, u32 *ale_entry, u16 vid, int untag_mask) { - cpsw_ale_set_vlan_untag_force(ale_entry, - untag_mask, ale->vlan_field_bits); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_FORCE_UNTAGGED_MSK, + untag_mask); if (untag_mask & ALE_PORT_HOST) bitmap_set(ale->p0_untag_vid_mask, vid, 1); else @@ -454,17 +609,19 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag, cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag); if (!ale->params.nu_switch_ale) { - cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast, - ale->vlan_field_bits); - cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast, - ale->vlan_field_bits); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_REG_MCAST_MSK, reg_mcast); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast); } else { - cpsw_ale_set_vlan_unreg_mcast_idx(ale_entry, - NU_VLAN_UNREG_MCAST_IDX); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_IDX, + NU_VLAN_UNREG_MCAST_IDX); cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, unreg_mcast); } - cpsw_ale_set_vlan_member_list(ale_entry, port_mask, - ale->vlan_field_bits); + + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_MEMBER_LIST, port_mask); if (idx < 0) idx = cpsw_ale_match_free(ale); @@ -483,20 +640,20 @@ static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry, int reg_mcast, unreg_mcast; int members, untag; - members = cpsw_ale_get_vlan_member_list(ale_entry, - ale->vlan_field_bits); + members = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_MEMBER_LIST); members &= ~port_mask; if (!members) { cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); return; } - untag = cpsw_ale_get_vlan_untag_force(ale_entry, - ale->vlan_field_bits); - reg_mcast = cpsw_ale_get_vlan_reg_mcast(ale_entry, - ale->vlan_field_bits); - unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry, - ale->vlan_field_bits); + untag = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_FORCE_UNTAGGED_MSK); + reg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_REG_MCAST_MSK); + unreg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK); untag &= members; reg_mcast &= members; unreg_mcast &= members; @@ -504,16 +661,16 @@ static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry, cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag); if (!ale->params.nu_switch_ale) { - cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast, - ale->vlan_field_bits); - cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast, - ale->vlan_field_bits); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_REG_MCAST_MSK, reg_mcast); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast); } else { cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, unreg_mcast); } - cpsw_ale_set_vlan_member_list(ale_entry, members, - ale->vlan_field_bits); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_MEMBER_LIST, members); } int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) @@ -551,15 +708,15 @@ int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, if (idx >= 0) cpsw_ale_read(ale, idx, ale_entry); - vlan_members = cpsw_ale_get_vlan_member_list(ale_entry, - ale->vlan_field_bits); - reg_mcast_members = cpsw_ale_get_vlan_reg_mcast(ale_entry, - ale->vlan_field_bits); + vlan_members = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_MEMBER_LIST); + reg_mcast_members = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_REG_MCAST_MSK); unreg_mcast_members = - cpsw_ale_get_vlan_unreg_mcast(ale_entry, - ale->vlan_field_bits); - untag_members = cpsw_ale_get_vlan_untag_force(ale_entry, - ale->vlan_field_bits); + cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK); + untag_members = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_FORCE_UNTAGGED_MSK); vlan_members |= port_mask; untag_members = (untag_members & ~port_mask) | untag_mask; @@ -592,14 +749,15 @@ void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, continue; unreg_members = - cpsw_ale_get_vlan_unreg_mcast(ale_entry, - ale->vlan_field_bits); + cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK); if (add) unreg_members |= unreg_mcast_mask; else unreg_members &= ~unreg_mcast_mask; - cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_members, - ale->vlan_field_bits); + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK, + unreg_members); cpsw_ale_write(ale, idx, ale_entry); } } @@ -609,15 +767,15 @@ static void cpsw_ale_vlan_set_unreg_mcast(struct cpsw_ale *ale, u32 *ale_entry, { int unreg_mcast; - unreg_mcast = - cpsw_ale_get_vlan_unreg_mcast(ale_entry, - ale->vlan_field_bits); + unreg_mcast = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK); if (allmulti) unreg_mcast |= ALE_PORT_HOST; else unreg_mcast &= ~ALE_PORT_HOST; - cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast, - ale->vlan_field_bits); + + cpsw_ale_vlan_set_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_MSK, unreg_mcast); } static void @@ -627,7 +785,8 @@ cpsw_ale_vlan_set_unreg_mcast_idx(struct cpsw_ale *ale, u32 *ale_entry, int unreg_mcast; int idx; - idx = cpsw_ale_get_vlan_unreg_mcast_idx(ale_entry); + idx = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_UNREG_MCAST_IDX); unreg_mcast = readl(ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx)); @@ -651,9 +810,9 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port) type = cpsw_ale_get_entry_type(ale_entry); if (type != ALE_TYPE_VLAN) continue; - vlan_members = - cpsw_ale_get_vlan_member_list(ale_entry, - ale->vlan_field_bits); + + vlan_members = cpsw_ale_vlan_get_fld(ale, ale_entry, + ALE_ENT_VID_MEMBER_LIST); if (port != -1 && !(vlan_members & BIT(port))) continue; @@ -960,30 +1119,146 @@ static void cpsw_ale_timer(struct timer_list *t) } } +static void cpsw_ale_hw_aging_timer_start(struct cpsw_ale *ale) +{ + u32 aging_timer; + + aging_timer = ale->params.bus_freq / 1000000; + aging_timer *= ale->params.ale_ageout; + + if (aging_timer & ~ALE_AGING_TIMER_MASK) { + aging_timer = ALE_AGING_TIMER_MASK; + dev_warn(ale->params.dev, + "ALE aging timer overflow, set to max\n"); + } + + writel(aging_timer, ale->params.ale_regs + ALE_AGING_TIMER); +} + +static void cpsw_ale_hw_aging_timer_stop(struct cpsw_ale *ale) +{ + writel(0, ale->params.ale_regs + ALE_AGING_TIMER); +} + +static void cpsw_ale_aging_start(struct cpsw_ale *ale) +{ + if (!ale->params.ale_ageout) + return; + + if (ale->features & CPSW_ALE_F_HW_AUTOAGING) { + cpsw_ale_hw_aging_timer_start(ale); + return; + } + + timer_setup(&ale->timer, cpsw_ale_timer, 0); + ale->timer.expires = jiffies + ale->ageout; + add_timer(&ale->timer); +} + +static void cpsw_ale_aging_stop(struct cpsw_ale *ale) +{ + if (!ale->params.ale_ageout) + return; + + if (ale->features & CPSW_ALE_F_HW_AUTOAGING) { + cpsw_ale_hw_aging_timer_stop(ale); + return; + } + + del_timer_sync(&ale->timer); +} + void cpsw_ale_start(struct cpsw_ale *ale) { cpsw_ale_control_set(ale, 0, ALE_ENABLE, 1); cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); - timer_setup(&ale->timer, cpsw_ale_timer, 0); - if (ale->ageout) { - ale->timer.expires = jiffies + ale->ageout; - add_timer(&ale->timer); - } + cpsw_ale_aging_start(ale); } void cpsw_ale_stop(struct cpsw_ale *ale) { - del_timer_sync(&ale->timer); + cpsw_ale_aging_stop(ale); cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); } +static const struct cpsw_ale_dev_id cpsw_ale_id_match[] = { + { + /* am3/4/5, dra7. dm814x, 66ak2hk-gbe */ + .dev_id = "cpsw", + .tbl_entries = 1024, + .major_ver_mask = 0xff, + .vlan_entry_tbl = vlan_entry_cpsw, + }, + { + /* 66ak2h_xgbe */ + .dev_id = "66ak2h-xgbe", + .tbl_entries = 2048, + .major_ver_mask = 0xff, + .vlan_entry_tbl = vlan_entry_cpsw, + }, + { + .dev_id = "66ak2el", + .features = CPSW_ALE_F_STATUS_REG, + .major_ver_mask = 0x7, + .nu_switch_ale = true, + .vlan_entry_tbl = vlan_entry_nu, + }, + { + .dev_id = "66ak2g", + .features = CPSW_ALE_F_STATUS_REG, + .tbl_entries = 64, + .major_ver_mask = 0x7, + .nu_switch_ale = true, + .vlan_entry_tbl = vlan_entry_nu, + }, + { + .dev_id = "am65x-cpsw2g", + .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING, + .tbl_entries = 64, + .major_ver_mask = 0x7, + .nu_switch_ale = true, + .vlan_entry_tbl = vlan_entry_nu, + }, + { + .dev_id = "j721e-cpswxg", + .features = CPSW_ALE_F_STATUS_REG | CPSW_ALE_F_HW_AUTOAGING, + .major_ver_mask = 0x7, + .vlan_entry_tbl = vlan_entry_k3_cpswxg, + }, + { }, +}; + +static const struct +cpsw_ale_dev_id *cpsw_ale_match_id(const struct cpsw_ale_dev_id *id, + const char *dev_id) +{ + if (!dev_id) + return NULL; + + while (id->dev_id) { + if (strcmp(dev_id, id->dev_id) == 0) + return id; + id++; + } + return NULL; +} + struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) { + const struct cpsw_ale_dev_id *ale_dev_id; struct cpsw_ale *ale; u32 rev, ale_entries; + ale_dev_id = cpsw_ale_match_id(cpsw_ale_id_match, params->dev_id); + if (!ale_dev_id) + return ERR_PTR(-EINVAL); + + params->ale_entries = ale_dev_id->tbl_entries; + params->major_ver_mask = ale_dev_id->major_ver_mask; + params->nu_switch_ale = ale_dev_id->nu_switch_ale; + ale = devm_kzalloc(params->dev, sizeof(*ale), GFP_KERNEL); if (!ale) return ERR_PTR(-ENOMEM); @@ -997,10 +1272,10 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) ale->params = *params; ale->ageout = ale->params.ale_ageout * HZ; + ale->features = ale_dev_id->features; + ale->vlan_entry_tbl = ale_dev_id->vlan_entry_tbl; rev = readl_relaxed(ale->params.ale_regs + ALE_IDVER); - if (!ale->params.major_ver_mask) - ale->params.major_ver_mask = 0xff; ale->version = (ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask) << 8) | ALE_VERSION_MINOR(rev); @@ -1008,7 +1283,8 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) ALE_VERSION_MAJOR(rev, ale->params.major_ver_mask), ALE_VERSION_MINOR(rev)); - if (!ale->params.ale_entries) { + if (ale->features & CPSW_ALE_F_STATUS_REG && + !ale->params.ale_entries) { ale_entries = readl_relaxed(ale->params.ale_regs + ALE_STATUS) & ALE_STATUS_SIZE_MASK; @@ -1017,16 +1293,12 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) * table which shows the size as a multiple of 1024 entries. * For these, params.ale_entries will be set to zero. So * read the register and update the value of ale_entries. - * ALE table on NetCP lite, is much smaller and is indicated - * by a value of zero in ALE_STATUS. So use a default value - * of ALE_TABLE_SIZE_DEFAULT for this. Caller is expected - * to set the value of ale_entries for all other versions - * of ALE. + * return error if ale_entries is zero in ALE_STATUS. */ if (!ale_entries) - ale_entries = ALE_TABLE_SIZE_DEFAULT; - else - ale_entries *= ALE_TABLE_SIZE_MULTIPLIER; + return ERR_PTR(-EINVAL); + + ale_entries *= ALE_TABLE_SIZE_MULTIPLIER; ale->params.ale_entries = ale_entries; } dev_info(ale->params.dev, @@ -1079,3 +1351,8 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) data += ALE_ENTRY_WORDS; } } + +u32 cpsw_ale_get_num_entries(struct cpsw_ale *ale) +{ + return ale ? ale->params.ale_entries : 0; +} |