Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'eth-fbnic-support-rss-contexts-and-ntuple-filters'

Jakub Kicinski says:

====================
eth: fbnic: support RSS contexts and ntuple filters

Add support for RSS contexts and ntuple filters in fbnic.
The device has only one context, intended for use by TCP zero-copy Rx.

First two patches add a check we seem to be missing in the core,
to avoid having to copy it to all drivers.

$ ./drivers/net/hw/rss_ctx.py
KTAP version 1
1..16
ok 1 rss_ctx.test_rss_key_indir
ok 2 rss_ctx.test_rss_queue_reconfigure
ok 3 rss_ctx.test_rss_resize
ok 4 rss_ctx.test_hitless_key_update
ok 5 rss_ctx.test_rss_context
# Failed to create context 2, trying to test what we got
ok 6 rss_ctx.test_rss_context4 # SKIP Tested only 1 contexts, wanted 4
# Increasing queue count 44 -> 66
# Failed to create context 2, trying to test what we got
ok 7 rss_ctx.test_rss_context32 # SKIP Tested only 1 contexts, wanted 32
# Added only 1 out of 3 contexts
ok 8 rss_ctx.test_rss_context_dump
# Driver does not support rss + queue offset
ok 9 rss_ctx.test_rss_context_queue_reconfigure
ok 10 rss_ctx.test_rss_context_overlap
ok 11 rss_ctx.test_rss_context_overlap2 # SKIP Test requires at least 2 contexts, but device only has 1
ok 12 rss_ctx.test_rss_context_out_of_order # SKIP Test requires at least 4 contexts, but device only has 1
# Failed to create context 2, trying to test what we got
ok 13 rss_ctx.test_rss_context4_create_with_cfg # SKIP Tested only 1 contexts, wanted 4
ok 14 rss_ctx.test_flow_add_context_missing
ok 15 rss_ctx.test_delete_rss_context_busy
ok 16 rss_ctx.test_rss_ntuple_addition # SKIP Ntuple filter with RSS and nonzero action not supported
# Totals: pass:10 fail:0 xfail:0 xpass:0 skip:6 error:0
====================

Link: https://patch.msgid.link/20250206235334.1425329-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+1294 -11
+6
drivers/net/ethernet/meta/fbnic/fbnic.h
··· 60 60 u8 mac_addr_boundary; 61 61 u8 tce_tcam_last; 62 62 63 + /* IP TCAM */ 64 + struct fbnic_ip_addr ip_src[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES]; 65 + struct fbnic_ip_addr ip_dst[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES]; 66 + struct fbnic_ip_addr ipo_src[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES]; 67 + struct fbnic_ip_addr ipo_dst[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES]; 68 + 63 69 /* Number of TCQs/RCQs available on hardware */ 64 70 u16 max_num_queues; 65 71
+6
drivers/net/ethernet/meta/fbnic/fbnic_csr.h
··· 605 605 FBNIC_RPC_ACT_TBL0_DEST_EI = 4, 606 606 }; 607 607 608 + #define FBNIC_RPC_ACT_TBL0_Q_SEL CSR_BIT(4) 609 + #define FBNIC_RPC_ACT_TBL0_Q_ID CSR_GENMASK(15, 8) 608 610 #define FBNIC_RPC_ACT_TBL0_DMA_HINT CSR_GENMASK(24, 16) 609 611 #define FBNIC_RPC_ACT_TBL0_TS_ENA CSR_BIT(28) 612 + #define FBNIC_RPC_ACT_TBL0_ACT_TBL_IDX CSR_BIT(29) 610 613 #define FBNIC_RPC_ACT_TBL0_RSS_CTXT_ID CSR_BIT(30) 611 614 612 615 #define FBNIC_RPC_ACT_TBL1_DEFAULT 0x0840b /* 0x2102c */ ··· 680 677 681 678 #define FBNIC_RPC_TCAM_OUTER_IPSRC(m, n)\ 682 679 (0x08c00 + 0x08 * (n) + (m)) /* 0x023000 + 32*n + 4*m */ 680 + #define FBNIC_RPC_TCAM_IP_ADDR_VALUE CSR_GENMASK(15, 0) 681 + #define FBNIC_RPC_TCAM_IP_ADDR_MASK CSR_GENMASK(31, 16) 682 + 683 683 #define FBNIC_RPC_TCAM_OUTER_IPDST(m, n)\ 684 684 (0x08c48 + 0x08 * (n) + (m)) /* 0x023120 + 32*n + 4*m */ 685 685 #define FBNIC_RPC_TCAM_IPSRC(m, n)\
+138
drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c
··· 44 44 } 45 45 DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_mac_addr); 46 46 47 + static int fbnic_dbg_tce_tcam_show(struct seq_file *s, void *v) 48 + { 49 + struct fbnic_dev *fbd = s->private; 50 + int i, tcam_idx = 0; 51 + char hdr[80]; 52 + 53 + /* Generate Header */ 54 + snprintf(hdr, sizeof(hdr), "%3s %s %-17s %s\n", 55 + "Idx", "S", "TCAM Bitmap", "Addr/Mask"); 56 + seq_puts(s, hdr); 57 + fbnic_dbg_desc_break(s, strnlen(hdr, sizeof(hdr))); 58 + 59 + for (i = 0; i < ARRAY_SIZE(fbd->mac_addr); i++) { 60 + struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[i]; 61 + 62 + /* Verify BMC bit is set */ 63 + if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) 64 + continue; 65 + 66 + if (tcam_idx == FBNIC_TCE_TCAM_NUM_ENTRIES) 67 + break; 68 + 69 + seq_printf(s, "%02d %d %64pb %pm\n", 70 + tcam_idx, mac_addr->state, mac_addr->act_tcam, 71 + mac_addr->value.addr8); 72 + seq_printf(s, " %pm\n", 73 + mac_addr->mask.addr8); 74 + tcam_idx++; 75 + } 76 + 77 + return 0; 78 + } 79 + DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_tce_tcam); 80 + 81 + static int fbnic_dbg_act_tcam_show(struct seq_file *s, void *v) 82 + { 83 + struct fbnic_dev *fbd = s->private; 84 + char hdr[80]; 85 + int i; 86 + 87 + /* Generate Header */ 88 + snprintf(hdr, sizeof(hdr), "%3s %s %-55s %-4s %s\n", 89 + "Idx", "S", "Value/Mask", "RSS", "Dest"); 90 + seq_puts(s, hdr); 91 + fbnic_dbg_desc_break(s, strnlen(hdr, sizeof(hdr))); 92 + 93 + for (i = 0; i < FBNIC_RPC_TCAM_ACT_NUM_ENTRIES; i++) { 94 + struct fbnic_act_tcam *act_tcam = &fbd->act_tcam[i]; 95 + 96 + seq_printf(s, "%02d %d %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %08x\n", 97 + i, act_tcam->state, 98 + act_tcam->value.tcam[10], act_tcam->value.tcam[9], 99 + act_tcam->value.tcam[8], act_tcam->value.tcam[7], 100 + act_tcam->value.tcam[6], act_tcam->value.tcam[5], 101 + act_tcam->value.tcam[4], act_tcam->value.tcam[3], 102 + act_tcam->value.tcam[2], act_tcam->value.tcam[1], 103 + act_tcam->value.tcam[0], act_tcam->rss_en_mask, 104 + act_tcam->dest); 105 + seq_printf(s, " %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n", 106 + act_tcam->mask.tcam[10], act_tcam->mask.tcam[9], 107 + act_tcam->mask.tcam[8], act_tcam->mask.tcam[7], 108 + act_tcam->mask.tcam[6], act_tcam->mask.tcam[5], 109 + act_tcam->mask.tcam[4], act_tcam->mask.tcam[3], 110 + act_tcam->mask.tcam[2], act_tcam->mask.tcam[1], 111 + act_tcam->mask.tcam[0]); 112 + } 113 + 114 + return 0; 115 + } 116 + DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_act_tcam); 117 + 118 + static int fbnic_dbg_ip_addr_show(struct seq_file *s, 119 + struct fbnic_ip_addr *ip_addr) 120 + { 121 + char hdr[80]; 122 + int i; 123 + 124 + /* Generate Header */ 125 + snprintf(hdr, sizeof(hdr), "%3s %s %-17s %s %s\n", 126 + "Idx", "S", "TCAM Bitmap", "V", "Addr/Mask"); 127 + seq_puts(s, hdr); 128 + fbnic_dbg_desc_break(s, strnlen(hdr, sizeof(hdr))); 129 + 130 + for (i = 0; i < FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES; i++, ip_addr++) { 131 + seq_printf(s, "%02d %d %64pb %d %pi6\n", 132 + i, ip_addr->state, ip_addr->act_tcam, 133 + ip_addr->version, &ip_addr->value); 134 + seq_printf(s, " %pi6\n", 135 + &ip_addr->mask); 136 + } 137 + 138 + return 0; 139 + } 140 + 141 + static int fbnic_dbg_ip_src_show(struct seq_file *s, void *v) 142 + { 143 + struct fbnic_dev *fbd = s->private; 144 + 145 + return fbnic_dbg_ip_addr_show(s, fbd->ip_src); 146 + } 147 + DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_ip_src); 148 + 149 + static int fbnic_dbg_ip_dst_show(struct seq_file *s, void *v) 150 + { 151 + struct fbnic_dev *fbd = s->private; 152 + 153 + return fbnic_dbg_ip_addr_show(s, fbd->ip_dst); 154 + } 155 + DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_ip_dst); 156 + 157 + static int fbnic_dbg_ipo_src_show(struct seq_file *s, void *v) 158 + { 159 + struct fbnic_dev *fbd = s->private; 160 + 161 + return fbnic_dbg_ip_addr_show(s, fbd->ipo_src); 162 + } 163 + DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_ipo_src); 164 + 165 + static int fbnic_dbg_ipo_dst_show(struct seq_file *s, void *v) 166 + { 167 + struct fbnic_dev *fbd = s->private; 168 + 169 + return fbnic_dbg_ip_addr_show(s, fbd->ipo_dst); 170 + } 171 + DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_ipo_dst); 172 + 47 173 static int fbnic_dbg_pcie_stats_show(struct seq_file *s, void *v) 48 174 { 49 175 struct fbnic_dev *fbd = s->private; ··· 210 84 &fbnic_dbg_pcie_stats_fops); 211 85 debugfs_create_file("mac_addr", 0400, fbd->dbg_fbd, fbd, 212 86 &fbnic_dbg_mac_addr_fops); 87 + debugfs_create_file("tce_tcam", 0400, fbd->dbg_fbd, fbd, 88 + &fbnic_dbg_tce_tcam_fops); 89 + debugfs_create_file("act_tcam", 0400, fbd->dbg_fbd, fbd, 90 + &fbnic_dbg_act_tcam_fops); 91 + debugfs_create_file("ip_src", 0400, fbd->dbg_fbd, fbd, 92 + &fbnic_dbg_ip_src_fops); 93 + debugfs_create_file("ip_dst", 0400, fbd->dbg_fbd, fbd, 94 + &fbnic_dbg_ip_dst_fops); 95 + debugfs_create_file("ipo_src", 0400, fbd->dbg_fbd, fbd, 96 + &fbnic_dbg_ipo_src_fops); 97 + debugfs_create_file("ipo_dst", 0400, fbd->dbg_fbd, fbd, 98 + &fbnic_dbg_ipo_dst_fops); 213 99 } 214 100 215 101 void fbnic_dbg_fbd_exit(struct fbnic_dev *fbd)
+705
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
··· 4 4 #include <linux/ethtool.h> 5 5 #include <linux/netdevice.h> 6 6 #include <linux/pci.h> 7 + #include <net/ipv6.h> 7 8 8 9 #include "fbnic.h" 9 10 #include "fbnic_netdev.h" ··· 219 218 return 0; 220 219 } 221 220 221 + static int fbnic_get_cls_rule_all(struct fbnic_net *fbn, 222 + struct ethtool_rxnfc *cmd, 223 + u32 *rule_locs) 224 + { 225 + struct fbnic_dev *fbd = fbn->fbd; 226 + int i, cnt = 0; 227 + 228 + /* Report maximum rule count */ 229 + cmd->data = FBNIC_RPC_ACT_TBL_NFC_ENTRIES; 230 + 231 + for (i = 0; i < FBNIC_RPC_ACT_TBL_NFC_ENTRIES; i++) { 232 + int idx = i + FBNIC_RPC_ACT_TBL_NFC_OFFSET; 233 + struct fbnic_act_tcam *act_tcam; 234 + 235 + act_tcam = &fbd->act_tcam[idx]; 236 + if (act_tcam->state != FBNIC_TCAM_S_VALID) 237 + continue; 238 + 239 + if (rule_locs) { 240 + if (cnt == cmd->rule_cnt) 241 + return -EMSGSIZE; 242 + 243 + rule_locs[cnt] = i; 244 + } 245 + 246 + cnt++; 247 + } 248 + 249 + return cnt; 250 + } 251 + 252 + static int fbnic_get_cls_rule(struct fbnic_net *fbn, struct ethtool_rxnfc *cmd) 253 + { 254 + struct ethtool_rx_flow_spec *fsp; 255 + struct fbnic_dev *fbd = fbn->fbd; 256 + struct fbnic_act_tcam *act_tcam; 257 + int idx; 258 + 259 + fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; 260 + 261 + if (fsp->location >= FBNIC_RPC_ACT_TBL_NFC_ENTRIES) 262 + return -EINVAL; 263 + 264 + idx = fsp->location + FBNIC_RPC_ACT_TBL_NFC_OFFSET; 265 + act_tcam = &fbd->act_tcam[idx]; 266 + 267 + if (act_tcam->state != FBNIC_TCAM_S_VALID) 268 + return -EINVAL; 269 + 270 + /* Report maximum rule count */ 271 + cmd->data = FBNIC_RPC_ACT_TBL_NFC_ENTRIES; 272 + 273 + /* Set flow type field */ 274 + if (!(act_tcam->value.tcam[1] & FBNIC_RPC_TCAM_ACT1_IP_VALID)) { 275 + fsp->flow_type = ETHER_FLOW; 276 + if (!FIELD_GET(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX, 277 + act_tcam->mask.tcam[1])) { 278 + struct fbnic_mac_addr *mac_addr; 279 + 280 + idx = FIELD_GET(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX, 281 + act_tcam->value.tcam[1]); 282 + mac_addr = &fbd->mac_addr[idx]; 283 + 284 + ether_addr_copy(fsp->h_u.ether_spec.h_dest, 285 + mac_addr->value.addr8); 286 + eth_broadcast_addr(fsp->m_u.ether_spec.h_dest); 287 + } 288 + } else if (act_tcam->value.tcam[1] & 289 + FBNIC_RPC_TCAM_ACT1_OUTER_IP_VALID) { 290 + fsp->flow_type = IPV6_USER_FLOW; 291 + fsp->h_u.usr_ip6_spec.l4_proto = IPPROTO_IPV6; 292 + fsp->m_u.usr_ip6_spec.l4_proto = 0xff; 293 + 294 + if (!FIELD_GET(FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_IDX, 295 + act_tcam->mask.tcam[0])) { 296 + struct fbnic_ip_addr *ip_addr; 297 + int i; 298 + 299 + idx = FIELD_GET(FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_IDX, 300 + act_tcam->value.tcam[0]); 301 + ip_addr = &fbd->ipo_src[idx]; 302 + 303 + for (i = 0; i < 4; i++) { 304 + fsp->h_u.usr_ip6_spec.ip6src[i] = 305 + ip_addr->value.s6_addr32[i]; 306 + fsp->m_u.usr_ip6_spec.ip6src[i] = 307 + ~ip_addr->mask.s6_addr32[i]; 308 + } 309 + } 310 + 311 + if (!FIELD_GET(FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_IDX, 312 + act_tcam->mask.tcam[0])) { 313 + struct fbnic_ip_addr *ip_addr; 314 + int i; 315 + 316 + idx = FIELD_GET(FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_IDX, 317 + act_tcam->value.tcam[0]); 318 + ip_addr = &fbd->ipo_dst[idx]; 319 + 320 + for (i = 0; i < 4; i++) { 321 + fsp->h_u.usr_ip6_spec.ip6dst[i] = 322 + ip_addr->value.s6_addr32[i]; 323 + fsp->m_u.usr_ip6_spec.ip6dst[i] = 324 + ~ip_addr->mask.s6_addr32[i]; 325 + } 326 + } 327 + } else if ((act_tcam->value.tcam[1] & FBNIC_RPC_TCAM_ACT1_IP_IS_V6)) { 328 + if (act_tcam->value.tcam[1] & FBNIC_RPC_TCAM_ACT1_L4_VALID) { 329 + if (act_tcam->value.tcam[1] & 330 + FBNIC_RPC_TCAM_ACT1_L4_IS_UDP) 331 + fsp->flow_type = UDP_V6_FLOW; 332 + else 333 + fsp->flow_type = TCP_V6_FLOW; 334 + fsp->h_u.tcp_ip6_spec.psrc = 335 + cpu_to_be16(act_tcam->value.tcam[3]); 336 + fsp->m_u.tcp_ip6_spec.psrc = 337 + cpu_to_be16(~act_tcam->mask.tcam[3]); 338 + fsp->h_u.tcp_ip6_spec.pdst = 339 + cpu_to_be16(act_tcam->value.tcam[4]); 340 + fsp->m_u.tcp_ip6_spec.pdst = 341 + cpu_to_be16(~act_tcam->mask.tcam[4]); 342 + } else { 343 + fsp->flow_type = IPV6_USER_FLOW; 344 + } 345 + 346 + if (!FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPSRC_IDX, 347 + act_tcam->mask.tcam[0])) { 348 + struct fbnic_ip_addr *ip_addr; 349 + int i; 350 + 351 + idx = FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPSRC_IDX, 352 + act_tcam->value.tcam[0]); 353 + ip_addr = &fbd->ip_src[idx]; 354 + 355 + for (i = 0; i < 4; i++) { 356 + fsp->h_u.usr_ip6_spec.ip6src[i] = 357 + ip_addr->value.s6_addr32[i]; 358 + fsp->m_u.usr_ip6_spec.ip6src[i] = 359 + ~ip_addr->mask.s6_addr32[i]; 360 + } 361 + } 362 + 363 + if (!FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPDST_IDX, 364 + act_tcam->mask.tcam[0])) { 365 + struct fbnic_ip_addr *ip_addr; 366 + int i; 367 + 368 + idx = FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPDST_IDX, 369 + act_tcam->value.tcam[0]); 370 + ip_addr = &fbd->ip_dst[idx]; 371 + 372 + for (i = 0; i < 4; i++) { 373 + fsp->h_u.usr_ip6_spec.ip6dst[i] = 374 + ip_addr->value.s6_addr32[i]; 375 + fsp->m_u.usr_ip6_spec.ip6dst[i] = 376 + ~ip_addr->mask.s6_addr32[i]; 377 + } 378 + } 379 + } else { 380 + if (act_tcam->value.tcam[1] & FBNIC_RPC_TCAM_ACT1_L4_VALID) { 381 + if (act_tcam->value.tcam[1] & 382 + FBNIC_RPC_TCAM_ACT1_L4_IS_UDP) 383 + fsp->flow_type = UDP_V4_FLOW; 384 + else 385 + fsp->flow_type = TCP_V4_FLOW; 386 + fsp->h_u.tcp_ip4_spec.psrc = 387 + cpu_to_be16(act_tcam->value.tcam[3]); 388 + fsp->m_u.tcp_ip4_spec.psrc = 389 + cpu_to_be16(~act_tcam->mask.tcam[3]); 390 + fsp->h_u.tcp_ip4_spec.pdst = 391 + cpu_to_be16(act_tcam->value.tcam[4]); 392 + fsp->m_u.tcp_ip4_spec.pdst = 393 + cpu_to_be16(~act_tcam->mask.tcam[4]); 394 + } else { 395 + fsp->flow_type = IPV4_USER_FLOW; 396 + fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; 397 + } 398 + 399 + if (!FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPSRC_IDX, 400 + act_tcam->mask.tcam[0])) { 401 + struct fbnic_ip_addr *ip_addr; 402 + 403 + idx = FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPSRC_IDX, 404 + act_tcam->value.tcam[0]); 405 + ip_addr = &fbd->ip_src[idx]; 406 + 407 + fsp->h_u.usr_ip4_spec.ip4src = 408 + ip_addr->value.s6_addr32[3]; 409 + fsp->m_u.usr_ip4_spec.ip4src = 410 + ~ip_addr->mask.s6_addr32[3]; 411 + } 412 + 413 + if (!FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPDST_IDX, 414 + act_tcam->mask.tcam[0])) { 415 + struct fbnic_ip_addr *ip_addr; 416 + 417 + idx = FIELD_GET(FBNIC_RPC_TCAM_ACT0_IPDST_IDX, 418 + act_tcam->value.tcam[0]); 419 + ip_addr = &fbd->ip_dst[idx]; 420 + 421 + fsp->h_u.usr_ip4_spec.ip4dst = 422 + ip_addr->value.s6_addr32[3]; 423 + fsp->m_u.usr_ip4_spec.ip4dst = 424 + ~ip_addr->mask.s6_addr32[3]; 425 + } 426 + } 427 + 428 + /* Record action */ 429 + if (act_tcam->dest & FBNIC_RPC_ACT_TBL0_DROP) 430 + fsp->ring_cookie = RX_CLS_FLOW_DISC; 431 + else if (act_tcam->dest & FBNIC_RPC_ACT_TBL0_Q_SEL) 432 + fsp->ring_cookie = FIELD_GET(FBNIC_RPC_ACT_TBL0_Q_ID, 433 + act_tcam->dest); 434 + else 435 + fsp->flow_type |= FLOW_RSS; 436 + 437 + cmd->rss_context = FIELD_GET(FBNIC_RPC_ACT_TBL0_RSS_CTXT_ID, 438 + act_tcam->dest); 439 + 440 + return 0; 441 + } 442 + 222 443 static int fbnic_get_rxnfc(struct net_device *netdev, 223 444 struct ethtool_rxnfc *cmd, u32 *rule_locs) 224 445 { 225 446 struct fbnic_net *fbn = netdev_priv(netdev); 226 447 int ret = -EOPNOTSUPP; 448 + u32 special = 0; 227 449 228 450 switch (cmd->cmd) { 229 451 case ETHTOOL_GRXRINGS: ··· 455 231 break; 456 232 case ETHTOOL_GRXFH: 457 233 ret = fbnic_get_rss_hash_opts(fbn, cmd); 234 + break; 235 + case ETHTOOL_GRXCLSRULE: 236 + ret = fbnic_get_cls_rule(fbn, cmd); 237 + break; 238 + case ETHTOOL_GRXCLSRLCNT: 239 + rule_locs = NULL; 240 + special = RX_CLS_LOC_SPECIAL; 241 + fallthrough; 242 + case ETHTOOL_GRXCLSRLALL: 243 + ret = fbnic_get_cls_rule_all(fbn, cmd, rule_locs); 244 + if (ret < 0) 245 + break; 246 + 247 + cmd->data |= special; 248 + cmd->rule_cnt = ret; 249 + ret = 0; 458 250 break; 459 251 } 460 252 ··· 512 272 return 0; 513 273 } 514 274 275 + static int fbnic_cls_rule_any_loc(struct fbnic_dev *fbd) 276 + { 277 + int i; 278 + 279 + for (i = FBNIC_RPC_ACT_TBL_NFC_ENTRIES; i--;) { 280 + int idx = i + FBNIC_RPC_ACT_TBL_NFC_OFFSET; 281 + 282 + if (fbd->act_tcam[idx].state != FBNIC_TCAM_S_VALID) 283 + return i; 284 + } 285 + 286 + return -ENOSPC; 287 + } 288 + 289 + static int fbnic_set_cls_rule_ins(struct fbnic_net *fbn, 290 + const struct ethtool_rxnfc *cmd) 291 + { 292 + u16 flow_value = 0, flow_mask = 0xffff, ip_value = 0, ip_mask = 0xffff; 293 + u16 sport = 0, sport_mask = ~0, dport = 0, dport_mask = ~0; 294 + u16 misc = 0, misc_mask = ~0; 295 + u32 dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK, 296 + FBNIC_RPC_ACT_TBL0_DEST_HOST); 297 + struct fbnic_ip_addr *ip_src = NULL, *ip_dst = NULL; 298 + struct fbnic_mac_addr *mac_addr = NULL; 299 + struct ethtool_rx_flow_spec *fsp; 300 + struct fbnic_dev *fbd = fbn->fbd; 301 + struct fbnic_act_tcam *act_tcam; 302 + struct in6_addr *addr6, *mask6; 303 + struct in_addr *addr4, *mask4; 304 + int hash_idx, location; 305 + u32 flow_type; 306 + int idx, j; 307 + 308 + fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; 309 + 310 + if (fsp->location != RX_CLS_LOC_ANY) 311 + return -EINVAL; 312 + location = fbnic_cls_rule_any_loc(fbd); 313 + if (location < 0) 314 + return location; 315 + 316 + if (fsp->ring_cookie == RX_CLS_FLOW_DISC) { 317 + dest = FBNIC_RPC_ACT_TBL0_DROP; 318 + } else if (fsp->flow_type & FLOW_RSS) { 319 + if (cmd->rss_context == 1) 320 + dest |= FBNIC_RPC_ACT_TBL0_RSS_CTXT_ID; 321 + } else { 322 + u32 ring_idx = ethtool_get_flow_spec_ring(fsp->ring_cookie); 323 + 324 + if (ring_idx >= fbn->num_rx_queues) 325 + return -EINVAL; 326 + 327 + dest |= FBNIC_RPC_ACT_TBL0_Q_SEL | 328 + FIELD_PREP(FBNIC_RPC_ACT_TBL0_Q_ID, ring_idx); 329 + } 330 + 331 + idx = location + FBNIC_RPC_ACT_TBL_NFC_OFFSET; 332 + act_tcam = &fbd->act_tcam[idx]; 333 + 334 + /* Do not allow overwriting for now. 335 + * To support overwriting rules we will need to add logic to free 336 + * any IP or MACDA TCAMs that may be associated with the old rule. 337 + */ 338 + if (act_tcam->state != FBNIC_TCAM_S_DISABLED) 339 + return -EBUSY; 340 + 341 + flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_RSS); 342 + hash_idx = fbnic_get_rss_hash_idx(flow_type); 343 + 344 + switch (flow_type) { 345 + case UDP_V4_FLOW: 346 + udp4_flow: 347 + flow_value |= FBNIC_RPC_TCAM_ACT1_L4_IS_UDP; 348 + fallthrough; 349 + case TCP_V4_FLOW: 350 + tcp4_flow: 351 + flow_value |= FBNIC_RPC_TCAM_ACT1_L4_VALID; 352 + flow_mask &= ~(FBNIC_RPC_TCAM_ACT1_L4_IS_UDP | 353 + FBNIC_RPC_TCAM_ACT1_L4_VALID); 354 + 355 + sport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.psrc); 356 + sport_mask = ~be16_to_cpu(fsp->m_u.tcp_ip4_spec.psrc); 357 + dport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.pdst); 358 + dport_mask = ~be16_to_cpu(fsp->m_u.tcp_ip4_spec.pdst); 359 + goto ip4_flow; 360 + case IP_USER_FLOW: 361 + if (!fsp->m_u.usr_ip4_spec.proto) 362 + goto ip4_flow; 363 + if (fsp->m_u.usr_ip4_spec.proto != 0xff) 364 + return -EINVAL; 365 + if (fsp->h_u.usr_ip4_spec.proto == IPPROTO_UDP) 366 + goto udp4_flow; 367 + if (fsp->h_u.usr_ip4_spec.proto == IPPROTO_TCP) 368 + goto tcp4_flow; 369 + return -EINVAL; 370 + ip4_flow: 371 + addr4 = (struct in_addr *)&fsp->h_u.usr_ip4_spec.ip4src; 372 + mask4 = (struct in_addr *)&fsp->m_u.usr_ip4_spec.ip4src; 373 + if (mask4->s_addr) { 374 + ip_src = __fbnic_ip4_sync(fbd, fbd->ip_src, 375 + addr4, mask4); 376 + if (!ip_src) 377 + return -ENOSPC; 378 + 379 + set_bit(idx, ip_src->act_tcam); 380 + ip_value |= FBNIC_RPC_TCAM_ACT0_IPSRC_VALID | 381 + FIELD_PREP(FBNIC_RPC_TCAM_ACT0_IPSRC_IDX, 382 + ip_src - fbd->ip_src); 383 + ip_mask &= ~(FBNIC_RPC_TCAM_ACT0_IPSRC_VALID | 384 + FBNIC_RPC_TCAM_ACT0_IPSRC_IDX); 385 + } 386 + 387 + addr4 = (struct in_addr *)&fsp->h_u.usr_ip4_spec.ip4dst; 388 + mask4 = (struct in_addr *)&fsp->m_u.usr_ip4_spec.ip4dst; 389 + if (mask4->s_addr) { 390 + ip_dst = __fbnic_ip4_sync(fbd, fbd->ip_dst, 391 + addr4, mask4); 392 + if (!ip_dst) { 393 + if (ip_src && ip_src->state == FBNIC_TCAM_S_ADD) 394 + memset(ip_src, 0, sizeof(*ip_src)); 395 + return -ENOSPC; 396 + } 397 + 398 + set_bit(idx, ip_dst->act_tcam); 399 + ip_value |= FBNIC_RPC_TCAM_ACT0_IPDST_VALID | 400 + FIELD_PREP(FBNIC_RPC_TCAM_ACT0_IPDST_IDX, 401 + ip_dst - fbd->ip_dst); 402 + ip_mask &= ~(FBNIC_RPC_TCAM_ACT0_IPDST_VALID | 403 + FBNIC_RPC_TCAM_ACT0_IPDST_IDX); 404 + } 405 + flow_value |= FBNIC_RPC_TCAM_ACT1_IP_VALID | 406 + FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID; 407 + flow_mask &= ~(FBNIC_RPC_TCAM_ACT1_IP_IS_V6 | 408 + FBNIC_RPC_TCAM_ACT1_IP_VALID | 409 + FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID); 410 + break; 411 + case UDP_V6_FLOW: 412 + udp6_flow: 413 + flow_value |= FBNIC_RPC_TCAM_ACT1_L4_IS_UDP; 414 + fallthrough; 415 + case TCP_V6_FLOW: 416 + tcp6_flow: 417 + flow_value |= FBNIC_RPC_TCAM_ACT1_L4_VALID; 418 + flow_mask &= ~(FBNIC_RPC_TCAM_ACT1_L4_IS_UDP | 419 + FBNIC_RPC_TCAM_ACT1_L4_VALID); 420 + 421 + sport = be16_to_cpu(fsp->h_u.tcp_ip6_spec.psrc); 422 + sport_mask = ~be16_to_cpu(fsp->m_u.tcp_ip6_spec.psrc); 423 + dport = be16_to_cpu(fsp->h_u.tcp_ip6_spec.pdst); 424 + dport_mask = ~be16_to_cpu(fsp->m_u.tcp_ip6_spec.pdst); 425 + goto ipv6_flow; 426 + case IPV6_USER_FLOW: 427 + if (!fsp->m_u.usr_ip6_spec.l4_proto) 428 + goto ipv6_flow; 429 + 430 + if (fsp->m_u.usr_ip6_spec.l4_proto != 0xff) 431 + return -EINVAL; 432 + if (fsp->h_u.usr_ip6_spec.l4_proto == IPPROTO_UDP) 433 + goto udp6_flow; 434 + if (fsp->h_u.usr_ip6_spec.l4_proto == IPPROTO_TCP) 435 + goto tcp6_flow; 436 + if (fsp->h_u.usr_ip6_spec.l4_proto != IPPROTO_IPV6) 437 + return -EINVAL; 438 + 439 + addr6 = (struct in6_addr *)fsp->h_u.usr_ip6_spec.ip6src; 440 + mask6 = (struct in6_addr *)fsp->m_u.usr_ip6_spec.ip6src; 441 + if (!ipv6_addr_any(mask6)) { 442 + ip_src = __fbnic_ip6_sync(fbd, fbd->ipo_src, 443 + addr6, mask6); 444 + if (!ip_src) 445 + return -ENOSPC; 446 + 447 + set_bit(idx, ip_src->act_tcam); 448 + ip_value |= 449 + FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_VALID | 450 + FIELD_PREP(FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_IDX, 451 + ip_src - fbd->ipo_src); 452 + ip_mask &= 453 + ~(FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_VALID | 454 + FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_IDX); 455 + } 456 + 457 + addr6 = (struct in6_addr *)fsp->h_u.usr_ip6_spec.ip6dst; 458 + mask6 = (struct in6_addr *)fsp->m_u.usr_ip6_spec.ip6dst; 459 + if (!ipv6_addr_any(mask6)) { 460 + ip_dst = __fbnic_ip6_sync(fbd, fbd->ipo_dst, 461 + addr6, mask6); 462 + if (!ip_dst) { 463 + if (ip_src && ip_src->state == FBNIC_TCAM_S_ADD) 464 + memset(ip_src, 0, sizeof(*ip_src)); 465 + return -ENOSPC; 466 + } 467 + 468 + set_bit(idx, ip_dst->act_tcam); 469 + ip_value |= 470 + FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_VALID | 471 + FIELD_PREP(FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_IDX, 472 + ip_dst - fbd->ipo_dst); 473 + ip_mask &= ~(FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_VALID | 474 + FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_IDX); 475 + } 476 + 477 + flow_value |= FBNIC_RPC_TCAM_ACT1_OUTER_IP_VALID; 478 + flow_mask &= FBNIC_RPC_TCAM_ACT1_OUTER_IP_VALID; 479 + ipv6_flow: 480 + addr6 = (struct in6_addr *)fsp->h_u.usr_ip6_spec.ip6src; 481 + mask6 = (struct in6_addr *)fsp->m_u.usr_ip6_spec.ip6src; 482 + if (!ip_src && !ipv6_addr_any(mask6)) { 483 + ip_src = __fbnic_ip6_sync(fbd, fbd->ip_src, 484 + addr6, mask6); 485 + if (!ip_src) 486 + return -ENOSPC; 487 + 488 + set_bit(idx, ip_src->act_tcam); 489 + ip_value |= FBNIC_RPC_TCAM_ACT0_IPSRC_VALID | 490 + FIELD_PREP(FBNIC_RPC_TCAM_ACT0_IPSRC_IDX, 491 + ip_src - fbd->ip_src); 492 + ip_mask &= ~(FBNIC_RPC_TCAM_ACT0_IPSRC_VALID | 493 + FBNIC_RPC_TCAM_ACT0_IPSRC_IDX); 494 + } 495 + 496 + addr6 = (struct in6_addr *)fsp->h_u.usr_ip6_spec.ip6dst; 497 + mask6 = (struct in6_addr *)fsp->m_u.usr_ip6_spec.ip6dst; 498 + if (!ip_dst && !ipv6_addr_any(mask6)) { 499 + ip_dst = __fbnic_ip6_sync(fbd, fbd->ip_dst, 500 + addr6, mask6); 501 + if (!ip_dst) { 502 + if (ip_src && ip_src->state == FBNIC_TCAM_S_ADD) 503 + memset(ip_src, 0, sizeof(*ip_src)); 504 + return -ENOSPC; 505 + } 506 + 507 + set_bit(idx, ip_dst->act_tcam); 508 + ip_value |= FBNIC_RPC_TCAM_ACT0_IPDST_VALID | 509 + FIELD_PREP(FBNIC_RPC_TCAM_ACT0_IPDST_IDX, 510 + ip_dst - fbd->ip_dst); 511 + ip_mask &= ~(FBNIC_RPC_TCAM_ACT0_IPDST_VALID | 512 + FBNIC_RPC_TCAM_ACT0_IPDST_IDX); 513 + } 514 + 515 + flow_value |= FBNIC_RPC_TCAM_ACT1_IP_IS_V6 | 516 + FBNIC_RPC_TCAM_ACT1_IP_VALID | 517 + FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID; 518 + flow_mask &= ~(FBNIC_RPC_TCAM_ACT1_IP_IS_V6 | 519 + FBNIC_RPC_TCAM_ACT1_IP_VALID | 520 + FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID); 521 + break; 522 + case ETHER_FLOW: 523 + if (!is_zero_ether_addr(fsp->m_u.ether_spec.h_dest)) { 524 + u8 *addr = fsp->h_u.ether_spec.h_dest; 525 + u8 *mask = fsp->m_u.ether_spec.h_dest; 526 + 527 + /* Do not allow MAC addr of 0 */ 528 + if (is_zero_ether_addr(addr)) 529 + return -EINVAL; 530 + 531 + /* Only support full MAC address to avoid 532 + * conflicts with other MAC addresses. 533 + */ 534 + if (!is_broadcast_ether_addr(mask)) 535 + return -EINVAL; 536 + 537 + if (is_multicast_ether_addr(addr)) 538 + mac_addr = __fbnic_mc_sync(fbd, addr); 539 + else 540 + mac_addr = __fbnic_uc_sync(fbd, addr); 541 + 542 + if (!mac_addr) 543 + return -ENOSPC; 544 + 545 + set_bit(idx, mac_addr->act_tcam); 546 + flow_value |= 547 + FIELD_PREP(FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX, 548 + mac_addr - fbd->mac_addr); 549 + flow_mask &= ~FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX; 550 + } 551 + 552 + flow_value |= FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID; 553 + flow_mask &= ~FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID; 554 + break; 555 + default: 556 + return -EINVAL; 557 + } 558 + 559 + /* Write action table values */ 560 + act_tcam->dest = dest; 561 + act_tcam->rss_en_mask = fbnic_flow_hash_2_rss_en_mask(fbn, hash_idx); 562 + 563 + /* Write IP Match value/mask to action_tcam[0] */ 564 + act_tcam->value.tcam[0] = ip_value; 565 + act_tcam->mask.tcam[0] = ip_mask; 566 + 567 + /* Write flow type value/mask to action_tcam[1] */ 568 + act_tcam->value.tcam[1] = flow_value; 569 + act_tcam->mask.tcam[1] = flow_mask; 570 + 571 + /* Write error, DSCP, extra L4 matches to action_tcam[2] */ 572 + act_tcam->value.tcam[2] = misc; 573 + act_tcam->mask.tcam[2] = misc_mask; 574 + 575 + /* Write source/destination port values */ 576 + act_tcam->value.tcam[3] = sport; 577 + act_tcam->mask.tcam[3] = sport_mask; 578 + act_tcam->value.tcam[4] = dport; 579 + act_tcam->mask.tcam[4] = dport_mask; 580 + 581 + for (j = 5; j < FBNIC_RPC_TCAM_ACT_WORD_LEN; j++) 582 + act_tcam->mask.tcam[j] = 0xffff; 583 + 584 + act_tcam->state = FBNIC_TCAM_S_UPDATE; 585 + fsp->location = location; 586 + 587 + if (netif_running(fbn->netdev)) { 588 + fbnic_write_rules(fbd); 589 + if (ip_src || ip_dst) 590 + fbnic_write_ip_addr(fbd); 591 + if (mac_addr) 592 + fbnic_write_macda(fbd); 593 + } 594 + 595 + return 0; 596 + } 597 + 598 + static void fbnic_clear_nfc_macda(struct fbnic_net *fbn, 599 + unsigned int tcam_idx) 600 + { 601 + struct fbnic_dev *fbd = fbn->fbd; 602 + int idx; 603 + 604 + for (idx = ARRAY_SIZE(fbd->mac_addr); idx--;) 605 + __fbnic_xc_unsync(&fbd->mac_addr[idx], tcam_idx); 606 + 607 + /* Write updates to hardware */ 608 + if (netif_running(fbn->netdev)) 609 + fbnic_write_macda(fbd); 610 + } 611 + 612 + static void fbnic_clear_nfc_ip_addr(struct fbnic_net *fbn, 613 + unsigned int tcam_idx) 614 + { 615 + struct fbnic_dev *fbd = fbn->fbd; 616 + int idx; 617 + 618 + for (idx = ARRAY_SIZE(fbd->ip_src); idx--;) 619 + __fbnic_ip_unsync(&fbd->ip_src[idx], tcam_idx); 620 + for (idx = ARRAY_SIZE(fbd->ip_dst); idx--;) 621 + __fbnic_ip_unsync(&fbd->ip_dst[idx], tcam_idx); 622 + for (idx = ARRAY_SIZE(fbd->ipo_src); idx--;) 623 + __fbnic_ip_unsync(&fbd->ipo_src[idx], tcam_idx); 624 + for (idx = ARRAY_SIZE(fbd->ipo_dst); idx--;) 625 + __fbnic_ip_unsync(&fbd->ipo_dst[idx], tcam_idx); 626 + 627 + /* Write updates to hardware */ 628 + if (netif_running(fbn->netdev)) 629 + fbnic_write_ip_addr(fbd); 630 + } 631 + 632 + static int fbnic_set_cls_rule_del(struct fbnic_net *fbn, 633 + const struct ethtool_rxnfc *cmd) 634 + { 635 + struct ethtool_rx_flow_spec *fsp; 636 + struct fbnic_dev *fbd = fbn->fbd; 637 + struct fbnic_act_tcam *act_tcam; 638 + int idx; 639 + 640 + fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; 641 + 642 + if (fsp->location >= FBNIC_RPC_ACT_TBL_NFC_ENTRIES) 643 + return -EINVAL; 644 + 645 + idx = fsp->location + FBNIC_RPC_ACT_TBL_NFC_OFFSET; 646 + act_tcam = &fbd->act_tcam[idx]; 647 + 648 + if (act_tcam->state != FBNIC_TCAM_S_VALID) 649 + return -EINVAL; 650 + 651 + act_tcam->state = FBNIC_TCAM_S_DELETE; 652 + 653 + if ((act_tcam->value.tcam[1] & FBNIC_RPC_TCAM_ACT1_L2_MACDA_VALID) && 654 + (~act_tcam->mask.tcam[1] & FBNIC_RPC_TCAM_ACT1_L2_MACDA_IDX)) 655 + fbnic_clear_nfc_macda(fbn, idx); 656 + 657 + if ((act_tcam->value.tcam[0] & 658 + (FBNIC_RPC_TCAM_ACT0_IPSRC_VALID | 659 + FBNIC_RPC_TCAM_ACT0_IPDST_VALID | 660 + FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_VALID | 661 + FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_VALID)) && 662 + (~act_tcam->mask.tcam[0] & 663 + (FBNIC_RPC_TCAM_ACT0_IPSRC_IDX | 664 + FBNIC_RPC_TCAM_ACT0_IPDST_IDX | 665 + FBNIC_RPC_TCAM_ACT0_OUTER_IPSRC_IDX | 666 + FBNIC_RPC_TCAM_ACT0_OUTER_IPDST_IDX))) 667 + fbnic_clear_nfc_ip_addr(fbn, idx); 668 + 669 + if (netif_running(fbn->netdev)) 670 + fbnic_write_rules(fbd); 671 + 672 + return 0; 673 + } 674 + 515 675 static int fbnic_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) 516 676 { 517 677 struct fbnic_net *fbn = netdev_priv(netdev); ··· 920 280 switch (cmd->cmd) { 921 281 case ETHTOOL_SRXFH: 922 282 ret = fbnic_set_rss_hash_opts(fbn, cmd); 283 + break; 284 + case ETHTOOL_SRXCLSRLINS: 285 + ret = fbnic_set_cls_rule_ins(fbn, cmd); 286 + break; 287 + case ETHTOOL_SRXCLSRLDEL: 288 + ret = fbnic_set_cls_rule_del(fbn, cmd); 923 289 break; 924 290 } 925 291 ··· 1017 371 if (changes && netif_running(netdev)) 1018 372 fbnic_rss_reinit_hw(fbn->fbd, fbn); 1019 373 374 + return 0; 375 + } 376 + 377 + static int 378 + fbnic_modify_rxfh_context(struct net_device *netdev, 379 + struct ethtool_rxfh_context *ctx, 380 + const struct ethtool_rxfh_param *rxfh, 381 + struct netlink_ext_ack *extack) 382 + { 383 + struct fbnic_net *fbn = netdev_priv(netdev); 384 + const u32 *indir = rxfh->indir; 385 + unsigned int changes; 386 + 387 + if (!indir) 388 + indir = ethtool_rxfh_context_indir(ctx); 389 + 390 + changes = fbnic_set_indir(fbn, rxfh->rss_context, indir); 391 + if (changes && netif_running(netdev)) 392 + fbnic_rss_reinit_hw(fbn->fbd, fbn); 393 + 394 + return 0; 395 + } 396 + 397 + static int 398 + fbnic_create_rxfh_context(struct net_device *netdev, 399 + struct ethtool_rxfh_context *ctx, 400 + const struct ethtool_rxfh_param *rxfh, 401 + struct netlink_ext_ack *extack) 402 + { 403 + struct fbnic_net *fbn = netdev_priv(netdev); 404 + 405 + if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP) { 406 + NL_SET_ERR_MSG_MOD(extack, "RSS hash function not supported"); 407 + return -EOPNOTSUPP; 408 + } 409 + ctx->hfunc = ETH_RSS_HASH_TOP; 410 + 411 + if (!rxfh->indir) { 412 + u32 *indir = ethtool_rxfh_context_indir(ctx); 413 + unsigned int num_rx = fbn->num_rx_queues; 414 + unsigned int i; 415 + 416 + for (i = 0; i < FBNIC_RPC_RSS_TBL_SIZE; i++) 417 + indir[i] = ethtool_rxfh_indir_default(i, num_rx); 418 + } 419 + 420 + return fbnic_modify_rxfh_context(netdev, ctx, rxfh, extack); 421 + } 422 + 423 + static int 424 + fbnic_remove_rxfh_context(struct net_device *netdev, 425 + struct ethtool_rxfh_context *ctx, u32 rss_context, 426 + struct netlink_ext_ack *extack) 427 + { 428 + /* Nothing to do, contexts are allocated statically */ 1020 429 return 0; 1021 430 } 1022 431 ··· 1287 586 } 1288 587 1289 588 static const struct ethtool_ops fbnic_ethtool_ops = { 589 + .rxfh_max_num_contexts = FBNIC_RPC_RSS_TBL_COUNT, 1290 590 .get_drvinfo = fbnic_get_drvinfo, 1291 591 .get_regs_len = fbnic_get_regs_len, 1292 592 .get_regs = fbnic_get_regs, ··· 1300 598 .get_rxfh_indir_size = fbnic_get_rxfh_indir_size, 1301 599 .get_rxfh = fbnic_get_rxfh, 1302 600 .set_rxfh = fbnic_set_rxfh, 601 + .create_rxfh_context = fbnic_create_rxfh_context, 602 + .modify_rxfh_context = fbnic_modify_rxfh_context, 603 + .remove_rxfh_context = fbnic_remove_rxfh_context, 1303 604 .get_channels = fbnic_get_channels, 1304 605 .set_channels = fbnic_set_channels, 1305 606 .get_ts_info = fbnic_get_ts_info,
+1
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
··· 639 639 netdev->hw_features |= netdev->features; 640 640 netdev->vlan_features |= netdev->features; 641 641 netdev->hw_enc_features |= netdev->features; 642 + netdev->features |= NETIF_F_NTUPLE; 642 643 643 644 netdev->min_mtu = IPV6_MIN_MTU; 644 645 netdev->max_mtu = FBNIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN;
+355 -1
drivers/net/ethernet/meta/fbnic/fbnic_rpc.c
··· 3 3 4 4 #include <linux/etherdevice.h> 5 5 #include <linux/ethtool.h> 6 + #include <net/ipv6.h> 6 7 7 8 #include "fbnic.h" 8 9 #include "fbnic_netdev.h" ··· 61 60 #define FBNIC_FH_2_RSSEM_BIT(_fh, _rssem, _val) \ 62 61 FIELD_PREP(FBNIC_RPC_ACT_TBL1_RSS_ENA_##_rssem, \ 63 62 FIELD_GET(RXH_##_fh, _val)) 64 - static u16 fbnic_flow_hash_2_rss_en_mask(struct fbnic_net *fbn, int flow_type) 63 + u16 fbnic_flow_hash_2_rss_en_mask(struct fbnic_net *fbn, int flow_type) 65 64 { 66 65 u32 flow_hash = fbn->rss_flow_hash[flow_type]; 67 66 u32 rss_en_mask = 0; ··· 697 696 __fbnic_write_tce_tcam_rev(fbd); 698 697 else 699 698 __fbnic_write_tce_tcam(fbd); 699 + } 700 + 701 + struct fbnic_ip_addr *__fbnic_ip4_sync(struct fbnic_dev *fbd, 702 + struct fbnic_ip_addr *ip_addr, 703 + const struct in_addr *addr, 704 + const struct in_addr *mask) 705 + { 706 + struct fbnic_ip_addr *avail_addr = NULL; 707 + unsigned int i; 708 + 709 + /* Scan from top of list to bottom, filling bottom up. */ 710 + for (i = 0; i < FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES; i++, ip_addr++) { 711 + struct in6_addr *m = &ip_addr->mask; 712 + 713 + if (ip_addr->state == FBNIC_TCAM_S_DISABLED) { 714 + avail_addr = ip_addr; 715 + continue; 716 + } 717 + 718 + if (ip_addr->version != 4) 719 + continue; 720 + 721 + /* Drop avail_addr if mask is a subset of our current mask, 722 + * This prevents us from inserting a longer prefix behind a 723 + * shorter one. 724 + * 725 + * The mask is stored inverted value so as an example: 726 + * m ffff ffff ffff ffff ffff ffff ffff 0000 0000 727 + * mask 0000 0000 0000 0000 0000 0000 0000 ffff ffff 728 + * 729 + * "m" and "mask" represent typical IPv4 mask stored in 730 + * the TCAM and those provided by the stack. The code below 731 + * should return a non-zero result if there is a 0 stored 732 + * anywhere in "m" where "mask" has a 0. 733 + */ 734 + if (~m->s6_addr32[3] & ~mask->s_addr) { 735 + avail_addr = NULL; 736 + continue; 737 + } 738 + 739 + /* Check to see if the mask actually contains fewer bits than 740 + * our new mask "m". The XOR below should only result in 0 if 741 + * "m" is masking a bit that we are looking for in our new 742 + * "mask", we eliminated the 0^0 case with the check above. 743 + * 744 + * If it contains fewer bits we need to stop here, otherwise 745 + * we might be adding an unreachable rule. 746 + */ 747 + if (~(m->s6_addr32[3] ^ mask->s_addr)) 748 + break; 749 + 750 + if (ip_addr->value.s6_addr32[3] == addr->s_addr) { 751 + avail_addr = ip_addr; 752 + break; 753 + } 754 + } 755 + 756 + if (avail_addr && avail_addr->state == FBNIC_TCAM_S_DISABLED) { 757 + ipv6_addr_set(&avail_addr->value, 0, 0, 0, addr->s_addr); 758 + ipv6_addr_set(&avail_addr->mask, htonl(~0), htonl(~0), 759 + htonl(~0), ~mask->s_addr); 760 + avail_addr->version = 4; 761 + 762 + avail_addr->state = FBNIC_TCAM_S_ADD; 763 + } 764 + 765 + return avail_addr; 766 + } 767 + 768 + struct fbnic_ip_addr *__fbnic_ip6_sync(struct fbnic_dev *fbd, 769 + struct fbnic_ip_addr *ip_addr, 770 + const struct in6_addr *addr, 771 + const struct in6_addr *mask) 772 + { 773 + struct fbnic_ip_addr *avail_addr = NULL; 774 + unsigned int i; 775 + 776 + ip_addr = &ip_addr[FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES - 1]; 777 + 778 + /* Scan from bottom of list to top, filling top down. */ 779 + for (i = FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES; i--; ip_addr--) { 780 + struct in6_addr *m = &ip_addr->mask; 781 + 782 + if (ip_addr->state == FBNIC_TCAM_S_DISABLED) { 783 + avail_addr = ip_addr; 784 + continue; 785 + } 786 + 787 + if (ip_addr->version != 6) 788 + continue; 789 + 790 + /* Drop avail_addr if mask is a superset of our current mask. 791 + * This prevents us from inserting a longer prefix behind a 792 + * shorter one. 793 + * 794 + * The mask is stored inverted value so as an example: 795 + * m 0000 0000 0000 0000 0000 0000 0000 0000 0000 796 + * mask ffff ffff ffff ffff ffff ffff ffff ffff ffff 797 + * 798 + * "m" and "mask" represent typical IPv6 mask stored in 799 + * the TCAM and those provided by the stack. The code below 800 + * should return a non-zero result which will cause us 801 + * to drop the avail_addr value that might be cached 802 + * to prevent us from dropping a v6 address behind it. 803 + */ 804 + if ((m->s6_addr32[0] & mask->s6_addr32[0]) | 805 + (m->s6_addr32[1] & mask->s6_addr32[1]) | 806 + (m->s6_addr32[2] & mask->s6_addr32[2]) | 807 + (m->s6_addr32[3] & mask->s6_addr32[3])) { 808 + avail_addr = NULL; 809 + continue; 810 + } 811 + 812 + /* The previous test eliminated any overlap between the 813 + * two values so now we need to check for gaps. 814 + * 815 + * If the mask is equal to our current mask then it should 816 + * result with m ^ mask = ffff ffff, if however the value 817 + * stored in m is bigger then we should see a 0 appear 818 + * somewhere in the mask. 819 + */ 820 + if (~(m->s6_addr32[0] ^ mask->s6_addr32[0]) | 821 + ~(m->s6_addr32[1] ^ mask->s6_addr32[1]) | 822 + ~(m->s6_addr32[2] ^ mask->s6_addr32[2]) | 823 + ~(m->s6_addr32[3] ^ mask->s6_addr32[3])) 824 + break; 825 + 826 + if (ipv6_addr_cmp(&ip_addr->value, addr)) 827 + continue; 828 + 829 + avail_addr = ip_addr; 830 + break; 831 + } 832 + 833 + if (avail_addr && avail_addr->state == FBNIC_TCAM_S_DISABLED) { 834 + memcpy(&avail_addr->value, addr, sizeof(*addr)); 835 + ipv6_addr_set(&avail_addr->mask, 836 + ~mask->s6_addr32[0], ~mask->s6_addr32[1], 837 + ~mask->s6_addr32[2], ~mask->s6_addr32[3]); 838 + avail_addr->version = 6; 839 + 840 + avail_addr->state = FBNIC_TCAM_S_ADD; 841 + } 842 + 843 + return avail_addr; 844 + } 845 + 846 + int __fbnic_ip_unsync(struct fbnic_ip_addr *ip_addr, unsigned int tcam_idx) 847 + { 848 + if (!test_and_clear_bit(tcam_idx, ip_addr->act_tcam)) 849 + return -ENOENT; 850 + 851 + if (bitmap_empty(ip_addr->act_tcam, FBNIC_RPC_TCAM_ACT_NUM_ENTRIES)) 852 + ip_addr->state = FBNIC_TCAM_S_DELETE; 853 + 854 + return 0; 855 + } 856 + 857 + static void fbnic_clear_ip_src_entry(struct fbnic_dev *fbd, unsigned int idx) 858 + { 859 + int i; 860 + 861 + /* Invalidate entry and clear addr state info */ 862 + for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 863 + wr32(fbd, FBNIC_RPC_TCAM_IPSRC(idx, i), 0); 864 + } 865 + 866 + static void fbnic_clear_ip_dst_entry(struct fbnic_dev *fbd, unsigned int idx) 867 + { 868 + int i; 869 + 870 + /* Invalidate entry and clear addr state info */ 871 + for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 872 + wr32(fbd, FBNIC_RPC_TCAM_IPDST(idx, i), 0); 873 + } 874 + 875 + static void fbnic_clear_ip_outer_src_entry(struct fbnic_dev *fbd, 876 + unsigned int idx) 877 + { 878 + int i; 879 + 880 + /* Invalidate entry and clear addr state info */ 881 + for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 882 + wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(idx, i), 0); 883 + } 884 + 885 + static void fbnic_clear_ip_outer_dst_entry(struct fbnic_dev *fbd, 886 + unsigned int idx) 887 + { 888 + int i; 889 + 890 + /* Invalidate entry and clear addr state info */ 891 + for (i = 0; i <= FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 892 + wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(idx, i), 0); 893 + } 894 + 895 + static void fbnic_write_ip_src_entry(struct fbnic_dev *fbd, unsigned int idx, 896 + struct fbnic_ip_addr *ip_addr) 897 + { 898 + __be16 *mask, *value; 899 + int i; 900 + 901 + mask = &ip_addr->mask.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 902 + value = &ip_addr->value.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 903 + 904 + for (i = 0; i < FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 905 + wr32(fbd, FBNIC_RPC_TCAM_IPSRC(idx, i), 906 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_MASK, ntohs(*mask--)) | 907 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_VALUE, ntohs(*value--))); 908 + wrfl(fbd); 909 + 910 + /* Bit 129 is used to flag for v4/v6 */ 911 + wr32(fbd, FBNIC_RPC_TCAM_IPSRC(idx, i), 912 + (ip_addr->version == 6) | FBNIC_RPC_TCAM_VALIDATE); 913 + } 914 + 915 + static void fbnic_write_ip_dst_entry(struct fbnic_dev *fbd, unsigned int idx, 916 + struct fbnic_ip_addr *ip_addr) 917 + { 918 + __be16 *mask, *value; 919 + int i; 920 + 921 + mask = &ip_addr->mask.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 922 + value = &ip_addr->value.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 923 + 924 + for (i = 0; i < FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 925 + wr32(fbd, FBNIC_RPC_TCAM_IPDST(idx, i), 926 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_MASK, ntohs(*mask--)) | 927 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_VALUE, ntohs(*value--))); 928 + wrfl(fbd); 929 + 930 + /* Bit 129 is used to flag for v4/v6 */ 931 + wr32(fbd, FBNIC_RPC_TCAM_IPDST(idx, i), 932 + (ip_addr->version == 6) | FBNIC_RPC_TCAM_VALIDATE); 933 + } 934 + 935 + static void fbnic_write_ip_outer_src_entry(struct fbnic_dev *fbd, 936 + unsigned int idx, 937 + struct fbnic_ip_addr *ip_addr) 938 + { 939 + __be16 *mask, *value; 940 + int i; 941 + 942 + mask = &ip_addr->mask.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 943 + value = &ip_addr->value.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 944 + 945 + for (i = 0; i < FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 946 + wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(idx, i), 947 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_MASK, ntohs(*mask--)) | 948 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_VALUE, ntohs(*value--))); 949 + wrfl(fbd); 950 + 951 + wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(idx, i), FBNIC_RPC_TCAM_VALIDATE); 952 + } 953 + 954 + static void fbnic_write_ip_outer_dst_entry(struct fbnic_dev *fbd, 955 + unsigned int idx, 956 + struct fbnic_ip_addr *ip_addr) 957 + { 958 + __be16 *mask, *value; 959 + int i; 960 + 961 + mask = &ip_addr->mask.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 962 + value = &ip_addr->value.s6_addr16[FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN - 1]; 963 + 964 + for (i = 0; i < FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN; i++) 965 + wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(idx, i), 966 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_MASK, ntohs(*mask--)) | 967 + FIELD_PREP(FBNIC_RPC_TCAM_IP_ADDR_VALUE, ntohs(*value--))); 968 + wrfl(fbd); 969 + 970 + wr32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(idx, i), FBNIC_RPC_TCAM_VALIDATE); 971 + } 972 + 973 + void fbnic_write_ip_addr(struct fbnic_dev *fbd) 974 + { 975 + int idx; 976 + 977 + for (idx = ARRAY_SIZE(fbd->ip_src); idx--;) { 978 + struct fbnic_ip_addr *ip_addr = &fbd->ip_src[idx]; 979 + 980 + /* Check if update flag is set else skip. */ 981 + if (!(ip_addr->state & FBNIC_TCAM_S_UPDATE)) 982 + continue; 983 + 984 + /* Clear by writing 0s. */ 985 + if (ip_addr->state == FBNIC_TCAM_S_DELETE) { 986 + /* Invalidate entry and clear addr state info */ 987 + fbnic_clear_ip_src_entry(fbd, idx); 988 + memset(ip_addr, 0, sizeof(*ip_addr)); 989 + 990 + continue; 991 + } 992 + 993 + fbnic_write_ip_src_entry(fbd, idx, ip_addr); 994 + 995 + ip_addr->state = FBNIC_TCAM_S_VALID; 996 + } 997 + 998 + /* Repeat process for other IP TCAMs */ 999 + for (idx = ARRAY_SIZE(fbd->ip_dst); idx--;) { 1000 + struct fbnic_ip_addr *ip_addr = &fbd->ip_dst[idx]; 1001 + 1002 + if (!(ip_addr->state & FBNIC_TCAM_S_UPDATE)) 1003 + continue; 1004 + 1005 + if (ip_addr->state == FBNIC_TCAM_S_DELETE) { 1006 + fbnic_clear_ip_dst_entry(fbd, idx); 1007 + memset(ip_addr, 0, sizeof(*ip_addr)); 1008 + 1009 + continue; 1010 + } 1011 + 1012 + fbnic_write_ip_dst_entry(fbd, idx, ip_addr); 1013 + 1014 + ip_addr->state = FBNIC_TCAM_S_VALID; 1015 + } 1016 + 1017 + for (idx = ARRAY_SIZE(fbd->ipo_src); idx--;) { 1018 + struct fbnic_ip_addr *ip_addr = &fbd->ipo_src[idx]; 1019 + 1020 + if (!(ip_addr->state & FBNIC_TCAM_S_UPDATE)) 1021 + continue; 1022 + 1023 + if (ip_addr->state == FBNIC_TCAM_S_DELETE) { 1024 + fbnic_clear_ip_outer_src_entry(fbd, idx); 1025 + memset(ip_addr, 0, sizeof(*ip_addr)); 1026 + 1027 + continue; 1028 + } 1029 + 1030 + fbnic_write_ip_outer_src_entry(fbd, idx, ip_addr); 1031 + 1032 + ip_addr->state = FBNIC_TCAM_S_VALID; 1033 + } 1034 + 1035 + for (idx = ARRAY_SIZE(fbd->ipo_dst); idx--;) { 1036 + struct fbnic_ip_addr *ip_addr = &fbd->ipo_dst[idx]; 1037 + 1038 + if (!(ip_addr->state & FBNIC_TCAM_S_UPDATE)) 1039 + continue; 1040 + 1041 + if (ip_addr->state == FBNIC_TCAM_S_DELETE) { 1042 + fbnic_clear_ip_outer_dst_entry(fbd, idx); 1043 + memset(ip_addr, 0, sizeof(*ip_addr)); 1044 + 1045 + continue; 1046 + } 1047 + 1048 + fbnic_write_ip_outer_dst_entry(fbd, idx, ip_addr); 1049 + 1050 + ip_addr->state = FBNIC_TCAM_S_VALID; 1051 + } 700 1052 } 701 1053 702 1054 void fbnic_clear_rules(struct fbnic_dev *fbd)
+35
drivers/net/ethernet/meta/fbnic/fbnic_rpc.h
··· 7 7 #include <uapi/linux/in6.h> 8 8 #include <linux/bitfield.h> 9 9 10 + struct in_addr; 11 + 10 12 /* The TCAM state definitions follow an expected ordering. 11 13 * They start out disabled, then move through the following states: 12 14 * Disabled 0 -> Add 2 ··· 34 32 #define FBNIC_RPC_TCAM_MACDA_WORD_LEN 3 35 33 #define FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES 32 36 34 35 + /* 8 IPSRC and IPDST TCAM Entries each 36 + * 8 registers, Validate each 37 + */ 38 + #define FBNIC_RPC_TCAM_IP_ADDR_WORD_LEN 8 39 + #define FBNIC_RPC_TCAM_IP_ADDR_NUM_ENTRIES 8 40 + 37 41 #define FBNIC_RPC_TCAM_ACT_WORD_LEN 11 38 42 #define FBNIC_RPC_TCAM_ACT_NUM_ENTRIES 64 39 43 ··· 51 43 unsigned char addr8[ETH_ALEN]; 52 44 __be16 addr16[FBNIC_RPC_TCAM_MACDA_WORD_LEN]; 53 45 } mask, value; 46 + unsigned char state; 47 + DECLARE_BITMAP(act_tcam, FBNIC_RPC_TCAM_ACT_NUM_ENTRIES); 48 + }; 49 + 50 + struct fbnic_ip_addr { 51 + struct in6_addr mask, value; 52 + unsigned char version; 54 53 unsigned char state; 55 54 DECLARE_BITMAP(act_tcam, FBNIC_RPC_TCAM_ACT_NUM_ENTRIES); 56 55 }; ··· 96 81 #define FBNIC_RPC_ACT_TBL_BMC_OFFSET 0 97 82 #define FBNIC_RPC_ACT_TBL_BMC_ALL_MULTI_OFFSET 1 98 83 84 + /* This should leave us with 48 total entries in the TCAM that can be used 85 + * for NFC after also deducting the 14 needed for RSS table programming. 86 + */ 87 + #define FBNIC_RPC_ACT_TBL_NFC_OFFSET 2 88 + 99 89 /* We reserve the last 14 entries for RSS rules on the host. The BMC 100 90 * unicast rule will need to be populated above these and is expected to 101 91 * use MACDA TCAM entry 23 to store the BMC MAC address. 102 92 */ 103 93 #define FBNIC_RPC_ACT_TBL_RSS_OFFSET \ 104 94 (FBNIC_RPC_ACT_TBL_NUM_ENTRIES - FBNIC_RSS_EN_NUM_ENTRIES) 95 + 96 + #define FBNIC_RPC_ACT_TBL_NFC_ENTRIES \ 97 + (FBNIC_RPC_ACT_TBL_RSS_OFFSET - FBNIC_RPC_ACT_TBL_NFC_OFFSET) 105 98 106 99 /* Flags used to identify the owner for this MAC filter. Note that any 107 100 * flags set for Broadcast thru Promisc indicate that the rule belongs ··· 191 168 void fbnic_rss_disable_hw(struct fbnic_dev *fbd); 192 169 void fbnic_rss_reinit_hw(struct fbnic_dev *fbd, struct fbnic_net *fbn); 193 170 void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn); 171 + u16 fbnic_flow_hash_2_rss_en_mask(struct fbnic_net *fbn, int flow_type); 194 172 195 173 int __fbnic_xc_unsync(struct fbnic_mac_addr *mac_addr, unsigned int tcam_idx); 196 174 struct fbnic_mac_addr *__fbnic_uc_sync(struct fbnic_dev *fbd, ··· 200 176 const unsigned char *addr); 201 177 void fbnic_sift_macda(struct fbnic_dev *fbd); 202 178 void fbnic_write_macda(struct fbnic_dev *fbd); 179 + 180 + struct fbnic_ip_addr *__fbnic_ip4_sync(struct fbnic_dev *fbd, 181 + struct fbnic_ip_addr *ip_addr, 182 + const struct in_addr *addr, 183 + const struct in_addr *mask); 184 + struct fbnic_ip_addr *__fbnic_ip6_sync(struct fbnic_dev *fbd, 185 + struct fbnic_ip_addr *ip_addr, 186 + const struct in6_addr *addr, 187 + const struct in6_addr *mask); 188 + int __fbnic_ip_unsync(struct fbnic_ip_addr *ip_addr, unsigned int tcam_idx); 189 + void fbnic_write_ip_addr(struct fbnic_dev *fbd); 203 190 204 191 static inline int __fbnic_uc_unsync(struct fbnic_mac_addr *mac_addr) 205 192 {
+8 -4
net/ethtool/ioctl.c
··· 993 993 return rc; 994 994 995 995 /* Nonzero ring with RSS only makes sense if NIC adds them together */ 996 - if (cmd == ETHTOOL_SRXCLSRLINS && info.fs.flow_type & FLOW_RSS && 997 - !ops->cap_rss_rxnfc_adds && 998 - ethtool_get_flow_spec_ring(info.fs.ring_cookie)) 999 - return -EINVAL; 996 + if (cmd == ETHTOOL_SRXCLSRLINS && info.fs.flow_type & FLOW_RSS) { 997 + if (!ops->cap_rss_rxnfc_adds && 998 + ethtool_get_flow_spec_ring(info.fs.ring_cookie)) 999 + return -EINVAL; 1000 + 1001 + if (!xa_load(&dev->ethtool->rss_ctx, info.rss_context)) 1002 + return -EINVAL; 1003 + } 1000 1004 1001 1005 if (cmd == ETHTOOL_SRXFH && ops->get_rxfh) { 1002 1006 struct ethtool_rxfh_param rxfh = {};
+40 -6
tools/testing/selftests/drivers/net/hw/rss_ctx.py
··· 4 4 import datetime 5 5 import random 6 6 import re 7 - from lib.py import ksft_run, ksft_pr, ksft_exit, ksft_eq, ksft_ne, ksft_ge, ksft_lt, ksft_true 7 + from lib.py import ksft_run, ksft_pr, ksft_exit 8 + from lib.py import ksft_eq, ksft_ne, ksft_ge, ksft_in, ksft_lt, ksft_true, ksft_raises 8 9 from lib.py import NetDrvEpEnv 9 10 from lib.py import EthtoolFamily, NetdevFamily 10 11 from lib.py import KsftSkipEx, KsftFailEx ··· 57 56 # ntuple is more of a capability than a config knob, don't bother 58 57 # trying to enable it (until some driver actually needs it). 59 58 raise KsftSkipEx("Ntuple filters not enabled on the device: " + str(features["ntuple-filters"])) 59 + 60 + 61 + def require_context_cnt(cfg, need_cnt): 62 + # There's no good API to get the context count, so the tests 63 + # which try to add a lot opportunisitically set the count they 64 + # discovered. Careful with test ordering! 65 + if need_cnt and cfg.context_cnt and cfg.context_cnt < need_cnt: 66 + raise KsftSkipEx(f"Test requires at least {need_cnt} contexts, but device only has {cfg.context_cnt}") 60 67 61 68 62 69 # Get Rx packet counts for all queues, as a simple list of integers ··· 465 456 raise 466 457 ksft_pr(f"Failed to create context {i + 1}, trying to test what we got") 467 458 ctx_cnt = i 459 + if cfg.context_cnt is None: 460 + cfg.context_cnt = ctx_cnt 468 461 break 469 462 470 463 _rss_key_check(cfg, context=ctx_id) ··· 522 511 """ 523 512 524 513 require_ntuple(cfg) 525 - 526 - requested_ctx_cnt = ctx_cnt 514 + require_context_cnt(cfg, 4) 527 515 528 516 # Try to allocate more queues when necessary 529 517 qcnt = len(_get_rx_cnts(cfg)) ··· 587 577 remove_ctx(-1) 588 578 check_traffic() 589 579 590 - if requested_ctx_cnt != ctx_cnt: 591 - raise KsftSkipEx(f"Tested only {ctx_cnt} contexts, wanted {requested_ctx_cnt}") 592 - 593 580 594 581 def test_rss_context_overlap(cfg, other_ctx=0): 595 582 """ ··· 595 588 """ 596 589 597 590 require_ntuple(cfg) 591 + if other_ctx: 592 + require_context_cnt(cfg, 2) 598 593 599 594 queue_cnt = len(_get_rx_cnts(cfg)) 600 595 if queue_cnt < 4: ··· 656 647 657 648 def test_rss_context_overlap2(cfg): 658 649 test_rss_context_overlap(cfg, True) 650 + 651 + 652 + def test_flow_add_context_missing(cfg): 653 + """ 654 + Test that we are not allowed to add a rule pointing to an RSS context 655 + which was never created. 656 + """ 657 + 658 + require_ntuple(cfg) 659 + 660 + # Find a context which doesn't exist 661 + for ctx_id in range(1, 100): 662 + try: 663 + get_rss(cfg, context=ctx_id) 664 + except CmdExitFailure: 665 + break 666 + 667 + with ksft_raises(CmdExitFailure) as cm: 668 + flow = f"flow-type tcp{cfg.addr_ipver} dst-ip {cfg.addr} dst-port 1234 context {ctx_id}" 669 + ntuple_id = ethtool_create(cfg, "-N", flow) 670 + ethtool(f"-N {cfg.ifname} delete {ntuple_id}") 671 + if cm.exception: 672 + ksft_in('Invalid argument', cm.exception.cmd.stderr) 659 673 660 674 661 675 def test_delete_rss_context_busy(cfg): ··· 749 717 750 718 def main() -> None: 751 719 with NetDrvEpEnv(__file__, nsim_test=False) as cfg: 720 + cfg.context_cnt = None 752 721 cfg.ethnl = EthtoolFamily() 753 722 cfg.netdevnl = NetdevFamily() 754 723 ··· 759 726 test_rss_context_dump, test_rss_context_queue_reconfigure, 760 727 test_rss_context_overlap, test_rss_context_overlap2, 761 728 test_rss_context_out_of_order, test_rss_context4_create_with_cfg, 729 + test_flow_add_context_missing, 762 730 test_delete_rss_context_busy, test_rss_ntuple_addition], 763 731 args=(cfg, )) 764 732 ksft_exit()