--- zzzz-none-000/linux-3.10.107/drivers/net/ethernet/ti/cpsw_ale.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/net/ethernet/ti/cpsw_ale.c 2021-02-04 17:41:59.000000000 +0000 @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ #include +#include #include #include #include @@ -25,8 +26,6 @@ #include "cpsw_ale.h" #define BITMASK(bits) (BIT(bits) - 1) -#define ALE_ENTRY_BITS 68 -#define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32) #define ALE_VERSION_MAJOR(rev) ((rev >> 8) & 0xff) #define ALE_VERSION_MINOR(rev) (rev & 0xff) @@ -148,7 +147,7 @@ return idx; } -int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) +static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; @@ -163,13 +162,13 @@ if (cpsw_ale_get_vlan_id(ale_entry) != vid) continue; cpsw_ale_get_addr(ale_entry, entry_addr); - if (memcmp(entry_addr, addr, 6) == 0) + if (ether_addr_equal(entry_addr, addr)) return idx; } return -ENOENT; } -int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) +static int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int type, idx; @@ -236,7 +235,7 @@ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); } -int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask) +int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid) { u32 ale_entry[ALE_ENTRY_WORDS]; int ret, idx; @@ -247,6 +246,14 @@ if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) continue; + /* if vid passed is -1 then remove all multicast entry from + * the table irrespective of vlan id, if a valid vlan id is + * passed then remove only multicast added to that vlan id. + * if vlan id doesn't match then move on to next entry. + */ + if (vid != -1 && cpsw_ale_get_vlan_id(ale_entry) != vid) + continue; + if (cpsw_ale_get_mcast(ale_entry)) { u8 addr[6]; @@ -259,38 +266,7 @@ } return 0; } - -static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry, - int port_mask) -{ - int port; - - port = cpsw_ale_get_port_num(ale_entry); - if ((BIT(port) & port_mask) == 0) - return; /* ports dont intersect, not interested */ - cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); -} - -int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) -{ - u32 ale_entry[ALE_ENTRY_WORDS]; - int ret, idx; - - for (idx = 0; idx < ale->params.ale_entries; idx++) { - cpsw_ale_read(ale, idx, ale_entry); - ret = cpsw_ale_get_entry_type(ale_entry); - if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) - continue; - - if (cpsw_ale_get_mcast(ale_entry)) - cpsw_ale_flush_mcast(ale, ale_entry, port_mask); - else - cpsw_ale_flush_ucast(ale, ale_entry, port_mask); - - cpsw_ale_write(ale, idx, ale_entry); - } - return 0; -} +EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast); static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, int flags, u16 vid) @@ -328,6 +304,7 @@ cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast); int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags, u16 vid) @@ -343,6 +320,7 @@ cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast); int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, int flags, u16 vid, int mcast_state) @@ -374,6 +352,7 @@ cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast); int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, int flags, u16 vid) @@ -395,6 +374,7 @@ cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast); int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, int reg_mcast, int unreg_mcast) @@ -424,6 +404,7 @@ cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan); int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) { @@ -444,6 +425,37 @@ cpsw_ale_write(ale, idx, ale_entry); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan); + +void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti) +{ + u32 ale_entry[ALE_ENTRY_WORDS]; + int type, idx; + int unreg_mcast = 0; + + /* Only bother doing the work if the setting is actually changing */ + if (ale->allmulti == allmulti) + return; + + /* Remember the new setting to check against next time */ + ale->allmulti = allmulti; + + for (idx = 0; idx < ale->params.ale_entries; idx++) { + cpsw_ale_read(ale, idx, ale_entry); + type = cpsw_ale_get_entry_type(ale_entry); + if (type != ALE_TYPE_VLAN) + continue; + + unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry); + if (allmulti) + unreg_mcast |= 1; + else + unreg_mcast &= ~1; + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); + cpsw_ale_write(ale, idx, ale_entry); + } +} +EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti); struct ale_control_info { const char *name; @@ -477,6 +489,14 @@ .port_shift = 0, .bits = 1, }, + [ALE_P0_UNI_FLOOD] = { + .name = "port0_unicast_flood", + .offset = ALE_CONTROL, + .port_offset = 0, + .shift = 8, + .port_shift = 0, + .bits = 1, + }, [ALE_VLAN_NOLEARN] = { .name = "vlan_nolearn", .offset = ALE_CONTROL, @@ -573,6 +593,14 @@ .port_shift = 0, .bits = 1, }, + [ALE_PORT_NO_SA_UPDATE] = { + .name = "no_source_update", + .offset = ALE_PORTCTL, + .port_offset = 4, + .shift = 5, + .port_shift = 0, + .bits = 1, + }, [ALE_PORT_MCAST_LIMIT] = { .name = "mcast_limit", .offset = ALE_PORTCTL, @@ -653,6 +681,7 @@ return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_control_set); int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control) { @@ -676,6 +705,7 @@ tmp = __raw_readl(ale->params.ale_regs + offset) >> shift; return tmp & BITMASK(info->bits); } +EXPORT_SYMBOL_GPL(cpsw_ale_control_get); static void cpsw_ale_timer(unsigned long arg) { @@ -689,17 +719,6 @@ } } -int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout) -{ - del_timer_sync(&ale->timer); - ale->ageout = ageout * HZ; - if (ale->ageout) { - ale->timer.expires = jiffies + ale->ageout; - add_timer(&ale->timer); - } - return 0; -} - void cpsw_ale_start(struct cpsw_ale *ale) { u32 rev; @@ -718,11 +737,13 @@ add_timer(&ale->timer); } } +EXPORT_SYMBOL_GPL(cpsw_ale_start); void cpsw_ale_stop(struct cpsw_ale *ale) { del_timer_sync(&ale->timer); } +EXPORT_SYMBOL_GPL(cpsw_ale_stop); struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) { @@ -737,13 +758,29 @@ return ale; } +EXPORT_SYMBOL_GPL(cpsw_ale_create); int cpsw_ale_destroy(struct cpsw_ale *ale) { if (!ale) return -EINVAL; - cpsw_ale_stop(ale); cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); kfree(ale); return 0; } +EXPORT_SYMBOL_GPL(cpsw_ale_destroy); + +void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data) +{ + int i; + + for (i = 0; i < ale->params.ale_entries; i++) { + cpsw_ale_read(ale, i, data); + data += ALE_ENTRY_WORDS; + } +} +EXPORT_SYMBOL_GPL(cpsw_ale_dump); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI CPSW ALE driver"); +MODULE_AUTHOR("Texas Instruments");