/** * t4vf_change_mac - modifies the exact-match filter for a MAC address * @adapter: the adapter * @viid: the Virtual Interface ID * @idx: index of existing filter for old value of MAC address, or -1 * @addr: the new MAC address value * @persist: if idx < 0, the new MAC allocation should be persistent * * Modifies an exact-match filter and sets it to the new MAC address. * Note that in general it is not possible to modify the value of a given * filter so the generic way to modify an address filter is to free the * one being used by the old address value and allocate a new filter for * the new address value. @idx can be -1 if the address is a new * addition. * * Returns a negative error number or the index of the filter with the new * MAC value. */ int t4vf_change_mac(struct adapter *adapter, unsigned int viid, int idx, const u8 *addr, bool persist) { int ret; struct fw_vi_mac_cmd cmd, rpl; struct fw_vi_mac_exact *p = &cmd.u.exact[0]; size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, u.exact[1]), 16); /* * If this is a new allocation, determine whether it should be * persistent (across a "freemacs" operation) or not. */ if (idx < 0) idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC; memset(&cmd, 0, sizeof(cmd)); cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | FW_CMD_WRITE | FW_VI_MAC_CMD_VIID(viid)); cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16(len16)); p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID | FW_VI_MAC_CMD_IDX(idx)); memcpy(p->macaddr, addr, sizeof(p->macaddr)); ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl); if (ret == 0) { p = &rpl.u.exact[0]; ret = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx)); if (ret >= FW_CLS_TCAM_NUM_ENTRIES) ret = -ENOMEM; } return ret; }
/** * t4vf_alloc_mac_filt - allocates exact-match filters for MAC addresses * @adapter: the adapter * @viid: the Virtual Interface Identifier * @free: if true any existing filters for this VI id are first removed * @naddr: the number of MAC addresses to allocate filters for (up to 7) * @addr: the MAC address(es) * @idx: where to store the index of each allocated filter * @hash: pointer to hash address filter bitmap * @sleep_ok: call is allowed to sleep * * Allocates an exact-match filter for each of the supplied addresses and * sets it to the corresponding address. If @idx is not %NULL it should * have at least @naddr entries, each of which will be set to the index of * the filter allocated for the corresponding MAC address. If a filter * could not be allocated for an address its index is set to 0xffff. * If @hash is not %NULL addresses that fail to allocate an exact filter * are hashed and update the hash filter bitmap pointed at by @hash. * * Returns a negative error number or the number of filters allocated. */ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, unsigned int naddr, const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok) { int offset, ret = 0; unsigned nfilters = 0; unsigned int rem = naddr; struct fw_vi_mac_cmd cmd, rpl; unsigned int max_naddr = is_t4(adapter->params.chip) ? NUM_MPS_CLS_SRAM_L_INSTANCES : NUM_MPS_T5_CLS_SRAM_L_INSTANCES; if (naddr > max_naddr) return -EINVAL; for (offset = 0; offset < naddr; /**/) { unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) ? rem : ARRAY_SIZE(cmd.u.exact)); size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, u.exact[fw_naddr]), 16); struct fw_vi_mac_exact *p; int i; memset(&cmd, 0, sizeof(cmd)); cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST | FW_CMD_WRITE | (free ? FW_CMD_EXEC : 0) | FW_VI_MAC_CMD_VIID(viid)); cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | FW_CMD_LEN16(len16)); for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) { p->valid_to_idx = cpu_to_be16( FW_VI_MAC_CMD_VALID | FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); } ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok); if (ret && ret != -ENOMEM) break; for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) { u16 index = FW_VI_MAC_CMD_IDX_GET( be16_to_cpu(p->valid_to_idx)); if (idx) idx[offset+i] = (index >= max_naddr ? 0xffff : index); if (index < max_naddr) nfilters++; else if (hash) *hash |= (1ULL << hash_mac_addr(addr[offset+i])); } free = false; offset += fw_naddr; rem -= fw_naddr; } /* * If there were no errors or we merely ran out of room in our MAC * address arena, return the number of filters actually written. */ if (ret == 0 || ret == -ENOMEM) ret = nfilters; return ret; }