/* * pnc_mac_da_mask - Add DA MAC address match rule to the MAC section * @da: destination MAC address * @mask: destination mask * @len: destination MAC address length to match on: 0..6 * @port_mask: source port id: 0..1F or ANY * @rxq: rx queue * @rinfo: result info bits to set */ static struct tcam_entry *pnc_mac_da_mask(unsigned char *da, unsigned char *mask, unsigned int len, unsigned int port_mask, int rxq, unsigned int rinfo) { struct tcam_entry *te = NULL; if (len > MV_MAC_ADDR_SIZE) goto out; if (rinfo >= BIT24) goto out; te = tcam_sw_alloc(TCAM_LU_MAC); /* set match on DA */ while (len--) { tcam_sw_set_byte(te, MV_ETH_MH_SIZE + len, da[len]); tcam_sw_set_mask(te, MV_ETH_MH_SIZE + len, mask[len]); } /* port id match */ tcam_sw_set_port(te, 0, port_mask); /* result info bit */ sram_sw_set_rinfo(te, rinfo); /* set rx queue */ sram_sw_set_rxq(te, rxq, 0); /* shift to ethertype */ sram_sw_set_shift_update(te, 0, MV_ETH_MH_SIZE + 2 * MV_MAC_ADDR_SIZE); sram_sw_set_next_lookup(te, TCAM_LU_L2); out: return te; }
/* * pnc_mcast_all - Accept all MAC multicast of port * @port: ingress giga port number. * @en: 1 - Accept ALL MCAST, 0 - Discard ALL MCAST */ int pnc_mcast_all(unsigned int port, int en) { struct tcam_entry *te; unsigned int data, mask; te = pnc_tcam_entry_get(TE_MAC_MC_ALL); if (te == NULL) { mvOsPrintf("%s: MC_ALL entry (tid=%d) is invalid\n", __func__, TE_MAC_MC_ALL); return 1; } /* Update port mask */ tcam_sw_get_port(te, &data, &mask); mask = pnc_port_mask_update(mask, port, en); tcam_sw_set_port(te, data, mask); tcam_sw_text(te, "mcast_all"); tcam_hw_write(te, TE_MAC_MC_ALL); tcam_sw_free(te); return 0; }
/* * pnc_mac_fc_drop - Add Flow Control MAC address match rule to the MAC section * to drop PAUSE frames arriving without Marvell Header on all ports */ static void pnc_mac_fc_drop(void) { struct tcam_entry *te = NULL; unsigned char da[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; unsigned int len = MV_MAC_ADDR_SIZE; te = tcam_sw_alloc(TCAM_LU_MAC); /* set match on DA */ while (len--) tcam_sw_set_byte(te, len, da[len]); /* port id match */ tcam_sw_set_port(te, 0, 0); /* all ports */ /* result info bit */ sram_sw_set_rinfo(te, RI_DROP); tcam_sw_text(te, "flow control"); sram_sw_set_lookup_done(te, 1); tcam_hw_write(te, TE_MAC_FLOW_CTRL); tcam_sw_free(te); }
static ssize_t tcam_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { const char* name = attr->attr.name; unsigned int err=0, a=0, b=0; unsigned long flags; if (!capable(CAP_NET_ADMIN)) return -EPERM; sscanf(buf,"%x %x",&a, &b); raw_local_irq_save(flags); if (!strcmp(name, "hw_write")) tcam_hw_write(&te, a); else if (!strcmp(name, "hw_read")) tcam_hw_read(&te, a); else if (!strcmp(name, "hw_debug")) tcam_hw_debug(a); else if (!strcmp(name, "hw_inv")) tcam_hw_inv(a); else if (!strcmp(name, "hw_inv_all")) tcam_hw_inv_all(); else if (!strcmp(name, "hw_hits")) tcam_hw_record(a); #ifdef CONFIG_MV_ETH_PNC_AGING else if (!strcmp(name, "age_clear")) mvPncAgingCntrClear(a); else if (!strcmp(name, "age_cntr")) { b = mvPncAgingCntrRead(a); printk("tid=%d: age_cntr = 0x%08x\n", a, b); } #endif /* CONFIG_MV_ETH_PNC_AGING */ else if (!strcmp(name, "sw_clear")) tcam_sw_clear(&te); else if (!strcmp(name, "sw_text")) { /* Remove last byte (new line) from the buffer */ int len = strlen(buf); char* temp = mvOsMalloc(len + 1); strncpy(temp, buf, len-1); temp[len-1] = 0; tcam_sw_text(&te, temp); mvOsFree(temp); } else if (!strcmp(name, "t_port")) tcam_sw_set_port(&te, a, b); else if (!strcmp(name, "t_lookup")) tcam_sw_set_lookup(&te, a); else if (!strcmp(name, "t_ainfo_0")) tcam_sw_set_ainfo(&te, 0<<a, 1<<a); else if (!strcmp(name, "t_ainfo_1")) tcam_sw_set_ainfo(&te, 1<<a, 1<<a); else if (!strcmp(name, "t_ainfo")) tcam_sw_set_ainfo(&te, a, b); else if (!strcmp(name, "t_offset_byte")) tcam_sw_set_byte(&te, a, b); else if (!strcmp(name, "t_offset_mask")) tcam_sw_set_mask(&te, a, b); else if (!strcmp(name, "s_lookup")) sram_sw_set_next_lookup(&te, a); else if (!strcmp(name, "s_ainfo")) sram_sw_set_ainfo(&te, a, b); else if (!strcmp(name, "s_lookup_done")) sram_sw_set_lookup_done(&te, a); else if (!strcmp(name, "s_next_lookup_shift")) sram_sw_set_next_lookup_shift(&te, a); else if (!strcmp(name, "s_rxq")) sram_sw_set_rxq(&te, a, b); else if (!strcmp(name, "s_shift_update")) sram_sw_set_shift_update(&te,a,b); else if (!strcmp(name, "s_rinfo")) sram_sw_set_rinfo(&te, 1 << a); else if (!strcmp(name, "s_rinfo_extra")) sram_sw_set_rinfo_extra(&te, a << (b & ~1)); else if (!strcmp(name, "s_flowid")) sram_sw_set_flowid(&te, a, b); else if (!strcmp(name, "s_flowid_nibble")) sram_sw_set_flowid_nibble(&te, a, b); #ifdef CONFIG_MV_ETH_PNC_AGING else if (!strcmp(name, "age_gr_set")) mvPncAgingCntrGroupSet(a, b); #endif /* CONFIG_MV_ETH_PNC_AGING */ else { err = 1; printk("%s: illegal operation <%s>\n", __FUNCTION__, attr->attr.name); } raw_local_irq_restore(flags); if (err) printk("%s: <%s>, error %d\n", __FUNCTION__, attr->attr.name, err); return err ? -EINVAL : len; }
/* * pnc_mcast_me - Add DA MAC address of port * @mac: Multicast MAC DA or NULL to delete all Multicast DAs for this port * @port: ingress giga port number */ int pnc_mcast_me(unsigned int port, unsigned char *mac) { struct tcam_entry *te; int tid, empty = -1; unsigned int data, mask; if (mac == NULL) { /* Delete all Multicast addresses for this port */ for (tid = (TE_MAC_MC_ALL + 1); tid <= TE_MAC_MC_L; tid++) { /* Check TCAM entry */ te = pnc_tcam_entry_get(tid); if (te != NULL) { /* delete entry if belong specific port */ tcam_sw_get_port(te, &data, &mask); mask = pnc_port_mask_update(mask, port, 0); if (mask == PORT_MASK) { /* No valid ports */ tcam_hw_inv(tid); } else { tcam_sw_set_port(te, data, mask); tcam_hw_write(te, tid); } tcam_sw_free(te); } } return 0; } /* Add new Multicast DA for this port */ for (tid = (TE_MAC_MC_ALL + 1); tid <= TE_MAC_MC_L; tid++) { te = pnc_tcam_entry_get(tid); /* Remember first Empty entry */ if (te == NULL) { if (empty == -1) empty = tid; continue; } /* Find existing TCAM entry with this DA */ if (tcam_sw_cmp_bytes(te, MV_ETH_MH_SIZE, MV_MAC_ADDR_SIZE, mac) == 0) { /* check and update port mask */ tcam_sw_get_port(te, &data, &mask); mask = pnc_port_mask_update(mask, port, 1); tcam_sw_set_port(te, data, mask); tcam_hw_write(te, tid); tcam_sw_free(te); return 0; } tcam_sw_free(te); } /* Not found existing entry and no free TCAM entry - Failed */ if (empty == -1) return 1; /* Not found existing entry - add to free TCAM entry */ te = pnc_mac_da(mac, MV_MAC_ADDR_SIZE, pnc_port_mask(port), rxq_mac_mc, RI_DA_MC); tcam_sw_text(te, "mcast_me"); tcam_hw_write(te, empty); tcam_sw_free(te); return 0; }