int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, int flags, u16 vid, int mcast_state) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; int idx, mask; idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); if (idx >= 0) cpsw_ale_read(ale, idx, ale_entry); cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); cpsw_ale_set_addr(ale_entry, addr); cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); cpsw_ale_set_mcast_state(ale_entry, mcast_state); mask = cpsw_ale_get_port_mask(ale_entry); port_mask |= mask; cpsw_ale_set_port_mask(ale_entry, port_mask); if (idx < 0) idx = cpsw_ale_match_free(ale); if (idx < 0) idx = cpsw_ale_find_ageable(ale); if (idx < 0) return -ENOMEM; cpsw_ale_write(ale, idx, ale_entry); return 0; }
int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; int idx, mask; idx = cpsw_ale_match_addr(ale, addr); if (idx >= 0) cpsw_ale_read(ale, idx, ale_entry); cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); cpsw_ale_set_addr(ale_entry, addr); cpsw_ale_set_mcast_state(ale_entry, ALE_MCAST_FWD_2); mask = cpsw_ale_get_port_mask(ale_entry); port_mask |= mask; cpsw_ale_set_port_mask(ale_entry, port_mask); if (idx < 0) idx = cpsw_ale_match_free(ale); if (idx < 0) idx = cpsw_ale_find_ageable(ale); if (idx < 0) return -ENOMEM; cpsw_ale_write(ale, idx, ale_entry); return 0; }
static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry, int port_mask) { int mask; mask = cpsw_ale_get_port_mask(ale_entry); if ((mask & port_mask) == 0) return; /* ports dont intersect, not interested */ mask &= ~port_mask; /* free if only remaining port is host port */ if (mask) cpsw_ale_set_port_mask(ale_entry, mask); else cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); }
static int cpsw_ale_dump_mcast(u32 *ale_entry, char *buf, int len) { int outlen = 0; static const char *str_mcast_state[] = {"f", "blf", "lf", "f"}; int mcast_state = cpsw_ale_get_mcast_state(ale_entry); int port_mask = cpsw_ale_get_port_mask(ale_entry); int super = cpsw_ale_get_super(ale_entry); outlen += snprintf(buf + outlen, len - outlen, "mcstate: %s(%d), ", str_mcast_state[mcast_state], mcast_state); outlen += snprintf(buf + outlen, len - outlen, "port mask: %x, %ssuper\n", port_mask, super ? "" : "no "); return outlen; }
int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; int idx, mask; idx = cpsw_ale_match_addr(ale, addr); if (idx < 0) return -EINVAL; cpsw_ale_read(ale, idx, ale_entry); mask = cpsw_ale_get_port_mask(ale_entry); port_mask = mask & ~port_mask; if (port_mask == BIT(ale->ale_ports)) cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); else cpsw_ale_set_port_mask(ale_entry, port_mask); cpsw_ale_write(ale, idx, ale_entry); return 0; }