for (i = 0; i < FBNIC_RPC_RSS_TBL_SIZE; i++) {
wr32(fbd, FBNIC_RPC_RSS_TBL(0, i), fbn->indir_tbl[0][i]);
wr32(fbd, FBNIC_RPC_RSS_TBL(1, i), fbn->indir_tbl[1][i]);
}
for (i = 0; i < FBNIC_RPC_RSS_KEY_DWORD_LEN; i++)
wr32(fbd, FBNIC_RPC_RSS_KEY(i), fbn->rss_key[i]);
/* Default action for this to drop w/ no destination */
wr32(fbd, FBNIC_RPC_ACT_TBL0_DEFAULT, FBNIC_RPC_ACT_TBL0_DROP);
wrfl(fbd);
wr32(fbd, FBNIC_RPC_ACT_TBL1_DEFAULT, 0);
/* If it isn't already enabled set the RMI Config value to enable RPC */
wr32(fbd, FBNIC_RPC_RMI_CONFIG,
FIELD_PREP(FBNIC_RPC_RMI_CONFIG_MTU, FBNIC_MAX_JUMBO_FRAME_SIZE) |
FIELD_PREP(FBNIC_RPC_RMI_CONFIG_OH_BYTES, 20) |
FBNIC_RPC_RMI_CONFIG_ENABLE);
}
/* We need to add the all multicast filter at the end of the *multicastaddresslist.Thiswayifthereareanythatare *sharedbetweenthehostandtheBMCtheycanbedirectedto *both.Otherwisetheremainderjustgetsentdirectlytothe *BMC.
*/
mac_addr = &fbd->mac_addr[fbd->mac_addr_boundary - 1]; if (fbnic_bmc_present(fbd) && fbd->fw_cap.all_multi) { if (mac_addr->state != FBNIC_TCAM_S_VALID) {
eth_zero_addr(mac_addr->value.addr8);
eth_broadcast_addr(mac_addr->mask.addr8);
mac_addr->value.addr8[0] ^= 1;
mac_addr->mask.addr8[0] ^= 1;
set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);
mac_addr->state = FBNIC_TCAM_S_ADD;
} if (enable_host)
set_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
mac_addr->act_tcam); else
clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI,
mac_addr->act_tcam);
} elseif (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam) &&
!is_zero_ether_addr(mac_addr->mask.addr8) &&
mac_addr->state == FBNIC_TCAM_S_VALID) {
clear_bit(FBNIC_MAC_ADDR_T_ALLMULTI, mac_addr->act_tcam);
clear_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);
mac_addr->state = FBNIC_TCAM_S_DELETE;
}
/* We have to add a special handler for multicast as the *BMCmayhaveanall-multirulealreadyinplace.Assuch *addingaruleourselveswon'tdoanygoodsowewillhave *tomodifytherulesfortheALLMULTIbelowiftheBMC *alreadyhastheruleinplace.
*/
act_tcam = &fbd->act_tcam[FBNIC_RPC_ACT_TBL_BMC_ALL_MULTI_OFFSET];
/* If we are not enabling the rule just delete it. We will fall *backtotheRSSrulesthatsupportthemulticastaddresses.
*/ if (!fbnic_bmc_present(fbd) || !fbd->fw_cap.all_multi || enable_host) { if (act_tcam->state == FBNIC_TCAM_S_VALID)
act_tcam->state = FBNIC_TCAM_S_DELETE; return;
}
/* Validate Broadcast is also present, record it and tag it */
mac_addr = &fbd->mac_addr[FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX];
eth_broadcast_addr(mac_addr->value.addr8);
set_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam);
mac_addr->state = FBNIC_TCAM_S_ADD;
/* Rewrite TCAM rule 0 if it isn't present to relocate BMC rules */
act_tcam = &fbd->act_tcam[FBNIC_RPC_ACT_TBL_BMC_OFFSET];
act_tcam->dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
FBNIC_RPC_ACT_TBL0_DEST_BMC);
act_tcam->mask.tcam[0] = 0xffff;
/* MACDA 0 - 3 is reserved for the BMC MAC address *toaccountforthatwehavetomaskoutthelower2bits *ofthemacdabyperformingan&=with0x1c.
*/
act_tcam->value.tcam[1] = FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
act_tcam->mask.tcam[1] = 0xffff &
~FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX, 0x1c) &
~FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
/* To support scenarios where a BMC is present we must write the *rulestwice,oncefortheunicastcases,andonceagainfor *thebroadcast/multicastcasesaswehavetosupport2destinations.
*/
BUILD_BUG_ON(FBNIC_RSS_EN_NUM_UNICAST * 2 != FBNIC_RSS_EN_NUM_ENTRIES);
BUILD_BUG_ON(ARRAY_SIZE(act1_value) != FBNIC_NUM_HASH_OPT);
/* Set timestamp mask with 1b per flow type */ if (fbn->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) { switch (fbn->hwtstamp_config.rx_filter) { case HWTSTAMP_FILTER_ALL:
tstamp_mask = FBNIC_TSTAMP_MASK(1, 1, 1); break; case HWTSTAMP_FILTER_PTP_V2_EVENT:
tstamp_mask = FBNIC_TSTAMP_MASK(0, 1, 1); break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
tstamp_mask = FBNIC_TSTAMP_MASK(0, 1, 0); break; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
tstamp_mask = FBNIC_TSTAMP_MASK(0, 0, 1); break; default:
netdev_warn(fbn->netdev, "Unsupported hwtstamp_rx_filter\n"); break;
}
}
/* Program RSS hash enable mask for host in action TCAM/table. */ for (i = fbnic_bmc_present(fbd) ? 0 : FBNIC_RSS_EN_NUM_UNICAST;
i < FBNIC_RSS_EN_NUM_ENTRIES; i++) { unsignedint idx = i + FBNIC_RPC_ACT_TBL_RSS_OFFSET; struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[idx];
u32 flow_hash, dest, rss_en_mask; int flow_type, j;
u16 value = 0;
flow_type = i % FBNIC_RSS_EN_NUM_UNICAST;
flow_hash = fbn->rss_flow_hash[flow_type];
/* Set DEST_HOST based on absence of RXH_DISCARD */
dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
!(RXH_DISCARD & flow_hash) ?
FBNIC_RPC_ACT_TBL0_DEST_HOST : 0);
if (i >= FBNIC_RSS_EN_NUM_UNICAST && fbnic_bmc_present(fbd))
dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
FBNIC_RPC_ACT_TBL0_DEST_BMC);
if (!dest)
dest = FBNIC_RPC_ACT_TBL0_DROP; elseif (tstamp_mask & (1u << flow_type))
dest |= FBNIC_RPC_ACT_TBL0_TS_ENA;
if (act1_value[flow_type] & FBNIC_RPC_TCAM_ACT1_L4_VALID)
dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT,
FBNIC_RCD_HDR_AL_DMA_HINT_L4);
/* We reserve the upper 8 MACDA TCAM entries for host *unicast.Sowesetthevalueto24,andthemaskthe *lowerbitssothatthelowerentriescanbeusedas *multicastorBMCaddresses.
*/ if (i < FBNIC_RSS_EN_NUM_UNICAST)
value = FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX,
fbd->mac_addr_boundary);
value |= FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID;
flow_type = i % FBNIC_RSS_EN_NUM_UNICAST;
value |= act1_value[flow_type];
/* Scan from middle of list to bottom, filling bottom up. *Skipthefirstentrywhichisreservedfordev_addrand *leavethelastentrytouseforpromiscuousfiltering.
*/ for (i = fbd->mac_addr_boundary - 1;
i < FBNIC_RPC_TCAM_MACDA_HOST_ADDR_IDX; i++) { struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
/* Scan from middle of list to top, filling top down. *SkipovertheaddressreservedfortheBMCMACand *excludeindex0asthatbelongstothebroadcastaddress
*/ for (i = fbd->mac_addr_boundary;
--i > FBNIC_RPC_TCAM_MACDA_BROADCAST_IDX;) { struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
/* Scan the BMC addresses to see if it may have already *reservedtheaddress.
*/ while (--i) { struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i];
if (!is_zero_ether_addr(mac_addr->mask.addr8)) continue;
/* Only move on if we find a match */ if (!ether_addr_equal(mac_addr->value.addr8, addr)) continue;
/* We need to pull this address to the shared area */ if (avail_addr) {
memcpy(avail_addr, mac_addr, sizeof(*mac_addr));
mac_addr->state = FBNIC_TCAM_S_DELETE;
avail_addr->state = FBNIC_TCAM_S_ADD;
}
if (mac_addr->state == FBNIC_TCAM_S_DISABLED) continue;
if (test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) { if (fbnic_bmc_present(fbd)) continue;
dev_warn_once(fbd->dev, "Found BMC MAC address w/ BMC not present\n");
}
fbnic_clear_macda_entry(fbd, idx);
/* If rule was already destined for deletion just wipe it now */ if (mac_addr->state == FBNIC_TCAM_S_DELETE) {
memset(mac_addr, 0, sizeof(*mac_addr)); continue;
}
/* Change state to update so that we will rewrite *thistcamthenexttimefbnic_write_macdaiscalled.
*/
mac_addr->state = FBNIC_TCAM_S_UPDATE;
}
}
/* Check if update flag is set else exit. */ if (!(mac_addr->state & FBNIC_TCAM_S_UPDATE)) continue;
/* Clear by writing 0s. */ if (mac_addr->state == FBNIC_TCAM_S_DELETE) { /* Invalidate entry and clear addr state info */
fbnic_clear_macda_entry(fbd, idx);
memset(mac_addr, 0, sizeof(*mac_addr));
continue;
}
fbnic_write_macda_entry(fbd, idx, mac_addr);
mac_addr->state = FBNIC_TCAM_S_VALID;
}
}
staticvoid fbnic_clear_act_tcam(struct fbnic_dev *fbd, unsignedint idx)
{ int i;
/* Invalidate entry and clear addr state info */ for (i = 0; i <= FBNIC_RPC_TCAM_ACT_WORD_LEN; i++)
wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i), 0);
}
staticvoid fbnic_clear_tce_tcam_entry(struct fbnic_dev *fbd, unsignedint idx)
{ int i;
/* Invalidate entry and clear addr state info */ for (i = 0; i <= FBNIC_TCE_TCAM_WORD_LEN; i++)
wr32(fbd, FBNIC_TCE_RAM_TCAM(idx, i), 0);
}
/* Scan from top of list to bottom, filling bottom up. */ for (i = 0; i < FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES; i++, ip_addr++) { struct in6_addr *m = &ip_addr->mask;
if (ip_addr->state == FBNIC_TCAM_S_DISABLED) {
avail_addr = ip_addr; continue;
}
if (ip_addr->version != 4) continue;
/* Drop avail_addr if mask is a subset of our current mask, *Thispreventsusfrominsertingalongerprefixbehinda *shorterone. * *Themaskisstoredinvertedvaluesoasanexample: *mffffffffffffffffffffffffffff00000000 *mask0000000000000000000000000000ffffffff * *"m"and"mask"representtypicalIPv4maskstoredin *theTCAMandthoseprovidedbythestack.Thecodebelow *shouldreturnanon-zeroresultifthereisa0stored *anywherein"m"where"mask"hasa0.
*/ if (~m->s6_addr32[3] & ~mask->s_addr) {
avail_addr = NULL; continue;
}
/* Check to see if the mask actually contains fewer bits than *ournewmask"m".TheXORbelowshouldonlyresultin0if *"m"ismaskingabitthatwearelookingforinournew *"mask",weeliminatedthe0^0casewiththecheckabove. * *Ifitcontainsfewerbitsweneedtostophere,otherwise *wemightbeaddinganunreachablerule.
*/ if (~(m->s6_addr32[3] ^ mask->s_addr)) break;
/* Scan from bottom of list to top, filling top down. */ for (i = FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES; i--; ip_addr--) { struct in6_addr *m = &ip_addr->mask;
if (ip_addr->state == FBNIC_TCAM_S_DISABLED) {
avail_addr = ip_addr; continue;
}
if (ip_addr->version != 6) continue;
/* Drop avail_addr if mask is a superset of our current mask. *Thispreventsusfrominsertingalongerprefixbehinda *shorterone. * *Themaskisstoredinvertedvaluesoasanexample: *m000000000000000000000000000000000000 *maskffffffffffffffffffffffffffffffffffff * *"m"and"mask"representtypicalIPv6maskstoredin *theTCAMandthoseprovidedbythestack.Thecodebelow *shouldreturnanon-zeroresultwhichwillcauseus *todroptheavail_addrvaluethatmightbecached *topreventusfromdroppingav6addressbehindit.
*/ if ((m->s6_addr32[0] & mask->s6_addr32[0]) |
(m->s6_addr32[1] & mask->s6_addr32[1]) |
(m->s6_addr32[2] & mask->s6_addr32[2]) |
(m->s6_addr32[3] & mask->s6_addr32[3])) {
avail_addr = NULL; continue;
}
/* The previous test eliminated any overlap between the *twovaluessonowweneedtocheckforgaps. * *Ifthemaskisequaltoourcurrentmaskthenitshould *resultwithm^mask=ffffffff,ifhoweverthevalue *storedinmisbiggerthenweshouldseea0appear *somewhereinthemask.
*/ if (~(m->s6_addr32[0] ^ mask->s6_addr32[0]) |
~(m->s6_addr32[1] ^ mask->s6_addr32[1]) |
~(m->s6_addr32[2] ^ mask->s6_addr32[2]) |
~(m->s6_addr32[3] ^ mask->s6_addr32[3])) break;
if (ipv6_addr_cmp(&ip_addr->value, addr)) continue;
int __fbnic_ip_unsync(struct fbnic_ip_addr *ip_addr, unsignedint tcam_idx)
{ if (!test_and_clear_bit(tcam_idx, ip_addr->act_tcam)) return -ENOENT;
if (bitmap_empty(ip_addr->act_tcam, FBNIC_RPC_TCAM_ACT_NUM_ENTRIES))
ip_addr->state = FBNIC_TCAM_S_DELETE;
return0;
}
staticvoid fbnic_clear_ip_src_entry(struct fbnic_dev *fbd, unsignedint idx)
{ int i;
/* Invalidate entry and clear addr state info */ for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++)
wr32(fbd, FBNIC_RPC_TCAM_IPSRC(idx, i), 0);
}
staticvoid fbnic_clear_ip_dst_entry(struct fbnic_dev *fbd, unsignedint idx)
{ int i;
/* Invalidate entry and clear addr state info */ for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++)
wr32(fbd, FBNIC_RPC_TCAM_IPDST(idx, i), 0);
}
staticvoid fbnic_clear_ip_outer_src_entry(struct fbnic_dev *fbd, unsignedint idx)
{ int i;
/* Invalidate entry and clear addr state info */ for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++)
wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(idx, i), 0);
}
staticvoid fbnic_clear_ip_outer_dst_entry(struct fbnic_dev *fbd, unsignedint idx)
{ int i;
/* Invalidate entry and clear addr state info */ for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++)
wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(idx, i), 0);
}
/* Check if update flag is set else skip. */ if (!(ip_addr->state & FBNIC_TCAM_S_UPDATE)) continue;
/* Clear by writing 0s. */ if (ip_addr->state == FBNIC_TCAM_S_DELETE) { /* Invalidate entry and clear addr state info */
fbnic_clear_ip_src_entry(fbd, idx);
memset(ip_addr, 0, sizeof(*ip_addr));
continue;
}
fbnic_write_ip_src_entry(fbd, idx, ip_addr);
ip_addr->state = FBNIC_TCAM_S_VALID;
}
/* Repeat process for other IP TCAMs */ for (idx = ARRAY_SIZE(fbd->ip_dst); idx--;) { struct fbnic_ip_addr *ip_addr = &fbd->ip_dst[idx];
if (!(ip_addr->state & FBNIC_TCAM_S_UPDATE)) continue;
if (ip_addr->state == FBNIC_TCAM_S_DELETE) {
fbnic_clear_ip_dst_entry(fbd, idx);
memset(ip_addr, 0, sizeof(*ip_addr));
void fbnic_clear_rules(struct fbnic_dev *fbd)
{
u32 dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK,
FBNIC_RPC_ACT_TBL0_DEST_BMC); int i = FBNIC_RPC_TCAM_ACT_NUM_ENTRIES - 1; struct fbnic_act_tcam *act_tcam;
/* Clear MAC rules */
fbnic_clear_macda(fbd);
/* If BMC is present we need to preserve the last rule which *willbeusedtoroutetraffictotheBMCifitisreceived. * *AtthispointitshouldbetheonlyMACaddressintheMACDA *soanyunicastormulticasttrafficreceivedshouldberouted *toit.Soleavethelastruleinplace. * *Itwillberewrittentoaddthehostagainwhenwebring *theinterfacebackup.
*/ if (fbnic_bmc_present(fbd)) {
act_tcam = &fbd->act_tcam[i];
/* Update entry by writing the destination and RSS mask */
wr32(fbd, FBNIC_RPC_ACT_TBL0(idx), act_tcam->dest);
wr32(fbd, FBNIC_RPC_ACT_TBL1(idx), act_tcam->rss_en_mask);
/* Write new TCAM rule to hardware */ for (i = 0; i < FBNIC_RPC_TCAM_ACT_WORD_LEN; i++)
wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i),
FIELD_PREP(FBNIC_RPC_TCAM_ACT_MASK,
act_tcam->mask.tcam[i]) |
FIELD_PREP(FBNIC_RPC_TCAM_ACT_VALUE,
act_tcam->value.tcam[i]));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.