652 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) Meta Platforms, Inc. and affiliates. */3 4#include <linux/etherdevice.h>5#include <linux/ethtool.h>6 7#include "fbnic.h"8#include "fbnic_netdev.h"9#include "fbnic_rpc.h"10 11void fbnic_reset_indir_tbl(struct fbnic_net *fbn)12{13 unsigned int num_rx = fbn->num_rx_queues;14 unsigned int i;15 16 for (i = 0; i < FBNIC_RPC_RSS_TBL_SIZE; i++) {17 fbn->indir_tbl[0][i] = ethtool_rxfh_indir_default(i, num_rx);18 fbn->indir_tbl[1][i] = ethtool_rxfh_indir_default(i, num_rx);19 }20}21 22void fbnic_rss_key_fill(u32 *buffer)23{24 static u32 rss_key[FBNIC_RPC_RSS_KEY_DWORD_LEN];25 26 net_get_random_once(rss_key, sizeof(rss_key));27 rss_key[FBNIC_RPC_RSS_KEY_LAST_IDX] &= FBNIC_RPC_RSS_KEY_LAST_MASK;28 29 memcpy(buffer, rss_key, sizeof(rss_key));30}31 32#define RX_HASH_OPT_L4 \33 (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)34#define RX_HASH_OPT_L3 \35 (RXH_IP_SRC | RXH_IP_DST)36#define RX_HASH_OPT_L2 RXH_L2DA37 38void fbnic_rss_init_en_mask(struct fbnic_net *fbn)39{40 fbn->rss_flow_hash[FBNIC_TCP4_HASH_OPT] = RX_HASH_OPT_L4;41 fbn->rss_flow_hash[FBNIC_TCP6_HASH_OPT] = RX_HASH_OPT_L4;42 43 fbn->rss_flow_hash[FBNIC_UDP4_HASH_OPT] = RX_HASH_OPT_L3;44 fbn->rss_flow_hash[FBNIC_UDP6_HASH_OPT] = RX_HASH_OPT_L3;45 fbn->rss_flow_hash[FBNIC_IPV4_HASH_OPT] = RX_HASH_OPT_L3;46 fbn->rss_flow_hash[FBNIC_IPV6_HASH_OPT] = RX_HASH_OPT_L3;47 48 fbn->rss_flow_hash[FBNIC_ETHER_HASH_OPT] = RX_HASH_OPT_L2;49}50 51void fbnic_rss_disable_hw(struct fbnic_dev *fbd)52{53 /* Disable RPC by clearing enable bit and configuration */54 if (!fbnic_bmc_present(fbd))55 wr32(fbd, FBNIC_RPC_RMI_CONFIG,56 FIELD_PREP(FBNIC_RPC_RMI_CONFIG_OH_BYTES, 20));57}58 59#define FBNIC_FH_2_RSSEM_BIT(_fh, _rssem, _val) \60 FIELD_PREP(FBNIC_RPC_ACT_TBL1_RSS_ENA_##_rssem, \61 FIELD_GET(RXH_##_fh, _val))62static u16 fbnic_flow_hash_2_rss_en_mask(struct fbnic_net *fbn, int flow_type)63{64 u32 flow_hash = fbn->rss_flow_hash[flow_type];65 u32 rss_en_mask = 0;66 67 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L2DA, L2_DA, flow_hash);68 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP_SRC, IP_SRC, flow_hash);69 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP_DST, IP_DST, flow_hash);70 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_0_1, L4_SRC, flow_hash);71 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_2_3, L4_DST, flow_hash);72 73 return rss_en_mask;74}75 76void fbnic_rss_reinit_hw(struct fbnic_dev *fbd, struct fbnic_net *fbn)77{78 unsigned int i;79 80 for (i = 0; i < FBNIC_RPC_RSS_TBL_SIZE; i++) {81 wr32(fbd, FBNIC_RPC_RSS_TBL(0, i), fbn->indir_tbl[0][i]);82 wr32(fbd, FBNIC_RPC_RSS_TBL(1, i), fbn->indir_tbl[1][i]);83 }84 85 for (i = 0; i < FBNIC_RPC_RSS_KEY_DWORD_LEN; i++)86 wr32(fbd, FBNIC_RPC_RSS_KEY(i), fbn->rss_key[i]);87 88 /* Default action for this to drop w/ no destination */89 wr32(fbd, FBNIC_RPC_ACT_TBL0_DEFAULT, FBNIC_RPC_ACT_TBL0_DROP);90 wrfl(fbd);91 92 wr32(fbd, FBNIC_RPC_ACT_TBL1_DEFAULT, 0);93 94 /* If it isn't already enabled set the RMI Config value to enable RPC */95 wr32(fbd, FBNIC_RPC_RMI_CONFIG,96 FIELD_PREP(FBNIC_RPC_RMI_CONFIG_MTU, FBNIC_MAX_JUMBO_FRAME_SIZE) |97 FIELD_PREP(FBNIC_RPC_RMI_CONFIG_OH_BYTES, 20) |98 FBNIC_RPC_RMI_CONFIG_ENABLE);99}100 101void fbnic_bmc_rpc_all_multi_config(struct fbnic_dev *fbd,102 bool enable_host)103{104 struct fbnic_act_tcam *act_tcam;105 struct fbnic_mac_addr *mac_addr;106 int j;107 108 /* We need to add the all multicast filter at the end of the109 * multicast address list. This way if there are any that are110 * shared between the host and the BMC they can be directed to111 * both. Otherwise the remainder just get sent directly to the112 * BMC.113 */114 mac_addr = &fbd->mac_addr[fbd->mac_addr_boundary - 1];115 if (fbnic_bmc_present(fbd) && fbd->fw_cap.all_multi) {116 if (mac_addr->state != FBNIC_TCAM_S_VALID) {117 eth_zero_addr(mac_addr->value.addr8);118 eth_broadcast_addr(mac_addr->mask.addr8);119 mac_addr->value.addr8[0] ^= 1;120 mac_addr->mask.addr8[0] ^= 1;121 set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);122 mac_addr->state = FBNIC_TCAM_S_ADD;123 }124 if (enable_host)125 set_bit(FBNIC_MAC_ADDR_T_ALLMULTI,126 mac_addr->act_tcam);127 else128 clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI,129 mac_addr->act_tcam);130 } else if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam) &&131 !is_zero_ether_addr(mac_addr->mask.addr8) &&132 mac_addr->state == FBNIC_TCAM_S_VALID) {133 clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, mac_addr->act_tcam);134 clear_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);135 mac_addr->state = FBNIC_TCAM_S_DELETE;136 }137 138 /* We have to add a special handler for multicast as the139 * BMC may have an all-multi rule already in place. As such140 * adding a rule ourselves won't do any good so we will have141 * to modify the rules for the ALL MULTI below if the BMC142 * already has the rule in place.143 */144 act_tcam = &fbd->act_tcam[FBNIC_RPC_ACT_TBL_BMC_ALL_MULTI_OFFSET];145 146 /* If we are not enabling the rule just delete it. We will fall147 * back to the RSS rules that support the multicast addresses.148 */149 if (!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi || enable_host) {150 if (act_tcam->state == FBNIC_TCAM_S_VALID)151 act_tcam->state = FBNIC_TCAM_S_DELETE;152 return;153 }154 155 /* Rewrite TCAM rule 23 to handle BMC all-multi traffic */156 act_tcam->dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,157 FBNIC_RPC_ACT_TBL0_DEST_BMC);158 act_tcam->mask.tcam[0] = 0xffff;159 160 /* MACDA 0 - 3 is reserved for the BMC MAC address */161 act_tcam->value.tcam[1] =162 FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX,163 fbd->mac_addr_boundary - 1) |164 FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;165 act_tcam->mask.tcam[1] = 0xffff &166 ~FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX &167 ~FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;168 169 for (j = 2; j < FBNIC_RPC_TCAM_ACT_WORD_LEN; j++)170 act_tcam->mask.tcam[j] = 0xffff;171 172 act_tcam->state = FBNIC_TCAM_S_UPDATE;173}174 175void fbnic_bmc_rpc_init(struct fbnic_dev *fbd)176{177 int i = FBNIC_RPC_TCAM_MACDA_BMC_ADDR_IDX;178 struct fbnic_act_tcam *act_tcam;179 struct fbnic_mac_addr *mac_addr;180 int j;181 182 /* Check if BMC is present */183 if (!fbnic_bmc_present(fbd))184 return;185 186 /* Fetch BMC MAC addresses from firmware capabilities */187 for (j = 0; j < 4; j++) {188 u8 *bmc_mac = fbd->fw_cap.bmc_mac_addr[j];189 190 /* Validate BMC MAC addresses */191 if (is_zero_ether_addr(bmc_mac))192 continue;193 194 if (is_multicast_ether_addr(bmc_mac))195 mac_addr = __fbnic_mc_sync(fbd, bmc_mac);196 else197 mac_addr = &fbd->mac_addr[i++];198 199 if (!mac_addr) {200 netdev_err(fbd->netdev,201 "No slot for BMC MAC address[%d]\n", j);202 continue;203 }204 205 ether_addr_copy(mac_addr->value.addr8, bmc_mac);206 eth_zero_addr(mac_addr->mask.addr8);207 208 set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);209 mac_addr->state = FBNIC_TCAM_S_ADD;210 }211 212 /* Validate Broadcast is also present, record it and tag it */213 mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX];214 eth_broadcast_addr(mac_addr->value.addr8);215 set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);216 mac_addr->state = FBNIC_TCAM_S_ADD;217 218 /* Rewrite TCAM rule 0 if it isn't present to relocate BMC rules */219 act_tcam = &fbd->act_tcam[FBNIC_RPC_ACT_TBL_BMC_OFFSET];220 act_tcam->dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,221 FBNIC_RPC_ACT_TBL0_DEST_BMC);222 act_tcam->mask.tcam[0] = 0xffff;223 224 /* MACDA 0 - 3 is reserved for the BMC MAC address225 * to account for that we have to mask out the lower 2 bits226 * of the macda by performing an &= with 0x1c.227 */228 act_tcam->value.tcam[1] = FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;229 act_tcam->mask.tcam[1] = 0xffff &230 ~FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX, 0x1c) &231 ~FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;232 233 for (j = 2; j < FBNIC_RPC_TCAM_ACT_WORD_LEN; j++)234 act_tcam->mask.tcam[j] = 0xffff;235 236 act_tcam->state = FBNIC_TCAM_S_UPDATE;237 238 fbnic_bmc_rpc_all_multi_config(fbd, false);239}240 241#define FBNIC_ACT1_INIT(_l4, _udp, _ip, _v6) \242 (((_l4) ? FBNIC_RPC_TCAM_ACT1_L4_VALID : 0) | \243 ((_udp) ? FBNIC_RPC_TCAM_ACT1_L4_IS_UDP : 0) | \244 ((_ip) ? FBNIC_RPC_TCAM_ACT1_IP_VALID : 0) | \245 ((_v6) ? FBNIC_RPC_TCAM_ACT1_IP_IS_V6 : 0))246 247void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn)248{249 static const u32 act1_value[FBNIC_NUM_HASH_OPT] = {250 FBNIC_ACT1_INIT(1, 1, 1, 1), /* UDP6 */251 FBNIC_ACT1_INIT(1, 1, 1, 0), /* UDP4 */252 FBNIC_ACT1_INIT(1, 0, 1, 1), /* TCP6 */253 FBNIC_ACT1_INIT(1, 0, 1, 0), /* TCP4 */254 FBNIC_ACT1_INIT(0, 0, 1, 1), /* IP6 */255 FBNIC_ACT1_INIT(0, 0, 1, 0), /* IP4 */256 0 /* Ether */257 };258 unsigned int i;259 260 /* To support scenarios where a BMC is present we must write the261 * rules twice, once for the unicast cases, and once again for262 * the broadcast/multicast cases as we have to support 2 destinations.263 */264 BUILD_BUG_ON(FBNIC_RSS_EN_NUM_UNICAST * 2 != FBNIC_RSS_EN_NUM_ENTRIES);265 BUILD_BUG_ON(ARRAY_SIZE(act1_value) != FBNIC_NUM_HASH_OPT);266 267 /* Program RSS hash enable mask for host in action TCAM/table. */268 for (i = fbnic_bmc_present(fbd) ? 0 : FBNIC_RSS_EN_NUM_UNICAST;269 i < FBNIC_RSS_EN_NUM_ENTRIES; i++) {270 unsigned int idx = i + FBNIC_RPC_ACT_TBL_RSS_OFFSET;271 struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[idx];272 u32 flow_hash, dest, rss_en_mask;273 int flow_type, j;274 u16 value = 0;275 276 flow_type = i % FBNIC_RSS_EN_NUM_UNICAST;277 flow_hash = fbn->rss_flow_hash[flow_type];278 279 /* Set DEST_HOST based on absence of RXH_DISCARD */280 dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,281 !(RXH_DISCARD & flow_hash) ?282 FBNIC_RPC_ACT_TBL0_DEST_HOST : 0);283 284 if (i >= FBNIC_RSS_EN_NUM_UNICAST && fbnic_bmc_present(fbd))285 dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,286 FBNIC_RPC_ACT_TBL0_DEST_BMC);287 288 if (!dest)289 dest = FBNIC_RPC_ACT_TBL0_DROP;290 291 if (act1_value[flow_type] & FBNIC_RPC_TCAM_ACT1_L4_VALID)292 dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT,293 FBNIC_RCD_HDR_AL_DMA_HINT_L4);294 295 rss_en_mask = fbnic_flow_hash_2_rss_en_mask(fbn, flow_type);296 297 act_tcam->dest = dest;298 act_tcam->rss_en_mask = rss_en_mask;299 act_tcam->state = FBNIC_TCAM_S_UPDATE;300 301 act_tcam->mask.tcam[0] = 0xffff;302 303 /* We reserve the upper 8 MACDA TCAM entries for host304 * unicast. So we set the value to 24, and the mask the305 * lower bits so that the lower entries can be used as306 * multicast or BMC addresses.307 */308 if (i < FBNIC_RSS_EN_NUM_UNICAST)309 value = FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX,310 fbd->mac_addr_boundary);311 value |= FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;312 313 flow_type = i % FBNIC_RSS_EN_NUM_UNICAST;314 value |= act1_value[flow_type];315 316 act_tcam->value.tcam[1] = value;317 act_tcam->mask.tcam[1] = ~value;318 319 for (j = 2; j < FBNIC_RPC_TCAM_ACT_WORD_LEN; j++)320 act_tcam->mask.tcam[j] = 0xffff;321 322 act_tcam->state = FBNIC_TCAM_S_UPDATE;323 }324}325 326struct fbnic_mac_addr *__fbnic_uc_sync(struct fbnic_dev *fbd,327 const unsigned char *addr)328{329 struct fbnic_mac_addr *avail_addr = NULL;330 unsigned int i;331 332 /* Scan from middle of list to bottom, filling bottom up.333 * Skip the first entry which is reserved for dev_addr and334 * leave the last entry to use for promiscuous filtering.335 */336 for (i = fbd->mac_addr_boundary - 1;337 i < FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX; i++) {338 struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];339 340 if (mac_addr->state == FBNIC_TCAM_S_DISABLED) {341 avail_addr = mac_addr;342 } else if (ether_addr_equal(mac_addr->value.addr8, addr)) {343 avail_addr = mac_addr;344 break;345 }346 }347 348 if (avail_addr && avail_addr->state == FBNIC_TCAM_S_DISABLED) {349 ether_addr_copy(avail_addr->value.addr8, addr);350 eth_zero_addr(avail_addr->mask.addr8);351 avail_addr->state = FBNIC_TCAM_S_ADD;352 }353 354 return avail_addr;355}356 357struct fbnic_mac_addr *__fbnic_mc_sync(struct fbnic_dev *fbd,358 const unsigned char *addr)359{360 struct fbnic_mac_addr *avail_addr = NULL;361 unsigned int i;362 363 /* Scan from middle of list to top, filling top down.364 * Skip over the address reserved for the BMC MAC and365 * exclude index 0 as that belongs to the broadcast address366 */367 for (i = fbd->mac_addr_boundary;368 --i > FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX;) {369 struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];370 371 if (mac_addr->state == FBNIC_TCAM_S_DISABLED) {372 avail_addr = mac_addr;373 } else if (ether_addr_equal(mac_addr->value.addr8, addr)) {374 avail_addr = mac_addr;375 break;376 }377 }378 379 /* Scan the BMC addresses to see if it may have already380 * reserved the address.381 */382 while (--i) {383 struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];384 385 if (!is_zero_ether_addr(mac_addr->mask.addr8))386 continue;387 388 /* Only move on if we find a match */389 if (!ether_addr_equal(mac_addr->value.addr8, addr))390 continue;391 392 /* We need to pull this address to the shared area */393 if (avail_addr) {394 memcpy(avail_addr, mac_addr, sizeof(*mac_addr));395 mac_addr->state = FBNIC_TCAM_S_DELETE;396 avail_addr->state = FBNIC_TCAM_S_ADD;397 }398 399 break;400 }401 402 if (avail_addr && avail_addr->state == FBNIC_TCAM_S_DISABLED) {403 ether_addr_copy(avail_addr->value.addr8, addr);404 eth_zero_addr(avail_addr->mask.addr8);405 avail_addr->state = FBNIC_TCAM_S_ADD;406 }407 408 return avail_addr;409}410 411int __fbnic_xc_unsync(struct fbnic_mac_addr *mac_addr, unsigned int tcam_idx)412{413 if (!test_and_clear_bit(tcam_idx, mac_addr->act_tcam))414 return -ENOENT;415 416 if (bitmap_empty(mac_addr->act_tcam, FBNIC_RPC_TCAM_ACT_NUM_ENTRIES))417 mac_addr->state = FBNIC_TCAM_S_DELETE;418 419 return 0;420}421 422void fbnic_sift_macda(struct fbnic_dev *fbd)423{424 int dest, src;425 426 /* Move BMC only addresses back into BMC region */427 for (dest = FBNIC_RPC_TCAM_MACDA_BMC_ADDR_IDX,428 src = FBNIC_RPC_TCAM_MACDA_MULTICAST_IDX;429 ++dest < FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX &&430 src < fbd->mac_addr_boundary;) {431 struct fbnic_mac_addr *dest_addr = &fbd->mac_addr[dest];432 433 if (dest_addr->state != FBNIC_TCAM_S_DISABLED)434 continue;435 436 while (src < fbd->mac_addr_boundary) {437 struct fbnic_mac_addr *src_addr = &fbd->mac_addr[src++];438 439 /* Verify BMC bit is set */440 if (!test_bit(FBNIC_MAC_ADDR_T_BMC, src_addr->act_tcam))441 continue;442 443 /* Verify filter isn't already disabled */444 if (src_addr->state == FBNIC_TCAM_S_DISABLED ||445 src_addr->state == FBNIC_TCAM_S_DELETE)446 continue;447 448 /* Verify only BMC bit is set */449 if (bitmap_weight(src_addr->act_tcam,450 FBNIC_RPC_TCAM_ACT_NUM_ENTRIES) != 1)451 continue;452 453 /* Verify we are not moving wildcard address */454 if (!is_zero_ether_addr(src_addr->mask.addr8))455 continue;456 457 memcpy(dest_addr, src_addr, sizeof(*src_addr));458 src_addr->state = FBNIC_TCAM_S_DELETE;459 dest_addr->state = FBNIC_TCAM_S_ADD;460 }461 }462}463 464static void fbnic_clear_macda_entry(struct fbnic_dev *fbd, unsigned int idx)465{466 int i;467 468 /* Invalidate entry and clear addr state info */469 for (i = 0; i <= FBNIC_RPC_TCAM_MACDA_WORD_LEN; i++)470 wr32(fbd, FBNIC_RPC_TCAM_MACDA(idx, i), 0);471}472 473static void fbnic_clear_macda(struct fbnic_dev *fbd)474{475 int idx;476 477 for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) {478 struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[idx];479 480 if (mac_addr->state == FBNIC_TCAM_S_DISABLED)481 continue;482 483 if (test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) {484 if (fbnic_bmc_present(fbd))485 continue;486 dev_warn_once(fbd->dev,487 "Found BMC MAC address w/ BMC not present\n");488 }489 490 fbnic_clear_macda_entry(fbd, idx);491 492 /* If rule was already destined for deletion just wipe it now */493 if (mac_addr->state == FBNIC_TCAM_S_DELETE) {494 memset(mac_addr, 0, sizeof(*mac_addr));495 continue;496 }497 498 /* Change state to update so that we will rewrite499 * this tcam the next time fbnic_write_macda is called.500 */501 mac_addr->state = FBNIC_TCAM_S_UPDATE;502 }503}504 505static void fbnic_write_macda_entry(struct fbnic_dev *fbd, unsigned int idx,506 struct fbnic_mac_addr *mac_addr)507{508 __be16 *mask, *value;509 int i;510 511 mask = &mac_addr->mask.addr16[FBNIC_RPC_TCAM_MACDA_WORD_LEN - 1];512 value = &mac_addr->value.addr16[FBNIC_RPC_TCAM_MACDA_WORD_LEN - 1];513 514 for (i = 0; i < FBNIC_RPC_TCAM_MACDA_WORD_LEN; i++)515 wr32(fbd, FBNIC_RPC_TCAM_MACDA(idx, i),516 FIELD_PREP(FBNIC_RPC_TCAM_MACDA_MASK, ntohs(*mask--)) |517 FIELD_PREP(FBNIC_RPC_TCAM_MACDA_VALUE, ntohs(*value--)));518 519 wrfl(fbd);520 521 wr32(fbd, FBNIC_RPC_TCAM_MACDA(idx, i), FBNIC_RPC_TCAM_VALIDATE);522}523 524void fbnic_write_macda(struct fbnic_dev *fbd)525{526 int idx;527 528 for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) {529 struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[idx];530 531 /* Check if update flag is set else exit. */532 if (!(mac_addr->state & FBNIC_TCAM_S_UPDATE))533 continue;534 535 /* Clear by writing 0s. */536 if (mac_addr->state == FBNIC_TCAM_S_DELETE) {537 /* Invalidate entry and clear addr state info */538 fbnic_clear_macda_entry(fbd, idx);539 memset(mac_addr, 0, sizeof(*mac_addr));540 541 continue;542 }543 544 fbnic_write_macda_entry(fbd, idx, mac_addr);545 546 mac_addr->state = FBNIC_TCAM_S_VALID;547 }548}549 550static void fbnic_clear_act_tcam(struct fbnic_dev *fbd, unsigned int idx)551{552 int i;553 554 /* Invalidate entry and clear addr state info */555 for (i = 0; i <= FBNIC_RPC_TCAM_ACT_WORD_LEN; i++)556 wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i), 0);557}558 559void fbnic_clear_rules(struct fbnic_dev *fbd)560{561 u32 dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,562 FBNIC_RPC_ACT_TBL0_DEST_BMC);563 int i = FBNIC_RPC_TCAM_ACT_NUM_ENTRIES - 1;564 struct fbnic_act_tcam *act_tcam;565 566 /* Clear MAC rules */567 fbnic_clear_macda(fbd);568 569 /* If BMC is present we need to preserve the last rule which570 * will be used to route traffic to the BMC if it is received.571 *572 * At this point it should be the only MAC address in the MACDA573 * so any unicast or multicast traffic received should be routed574 * to it. So leave the last rule in place.575 *576 * It will be rewritten to add the host again when we bring577 * the interface back up.578 */579 if (fbnic_bmc_present(fbd)) {580 act_tcam = &fbd->act_tcam[i];581 582 if (act_tcam->state == FBNIC_TCAM_S_VALID &&583 (act_tcam->dest & dest)) {584 wr32(fbd, FBNIC_RPC_ACT_TBL0(i), dest);585 wr32(fbd, FBNIC_RPC_ACT_TBL1(i), 0);586 587 act_tcam->state = FBNIC_TCAM_S_UPDATE;588 589 i--;590 }591 }592 593 /* Work from the bottom up deleting all other rules from hardware */594 do {595 act_tcam = &fbd->act_tcam[i];596 597 if (act_tcam->state != FBNIC_TCAM_S_VALID)598 continue;599 600 fbnic_clear_act_tcam(fbd, i);601 act_tcam->state = FBNIC_TCAM_S_UPDATE;602 } while (i--);603}604 605static void fbnic_delete_act_tcam(struct fbnic_dev *fbd, unsigned int idx)606{607 fbnic_clear_act_tcam(fbd, idx);608 memset(&fbd->act_tcam[idx], 0, sizeof(struct fbnic_act_tcam));609}610 611static void fbnic_update_act_tcam(struct fbnic_dev *fbd, unsigned int idx)612{613 struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[idx];614 int i;615 616 /* Update entry by writing the destination and RSS mask */617 wr32(fbd, FBNIC_RPC_ACT_TBL0(idx), act_tcam->dest);618 wr32(fbd, FBNIC_RPC_ACT_TBL1(idx), act_tcam->rss_en_mask);619 620 /* Write new TCAM rule to hardware */621 for (i = 0; i < FBNIC_RPC_TCAM_ACT_WORD_LEN; i++)622 wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i),623 FIELD_PREP(FBNIC_RPC_TCAM_ACT_MASK,624 act_tcam->mask.tcam[i]) |625 FIELD_PREP(FBNIC_RPC_TCAM_ACT_VALUE,626 act_tcam->value.tcam[i]));627 628 wrfl(fbd);629 630 wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i), FBNIC_RPC_TCAM_VALIDATE);631 act_tcam->state = FBNIC_TCAM_S_VALID;632}633 634void fbnic_write_rules(struct fbnic_dev *fbd)635{636 int i;637 638 /* Flush any pending action table rules */639 for (i = 0; i < FBNIC_RPC_ACT_TBL_NUM_ENTRIES; i++) {640 struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[i];641 642 /* Check if update flag is set else exit. */643 if (!(act_tcam->state & FBNIC_TCAM_S_UPDATE))644 continue;645 646 if (act_tcam->state == FBNIC_TCAM_S_DELETE)647 fbnic_delete_act_tcam(fbd, i);648 else649 fbnic_update_act_tcam(fbd, i);650 }651}652