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

net: ethernet: mtk_eth_soc: support creating mac address based offload entries

This will be used to implement a limited form of bridge offloading.
Since the hardware does not support flow table entries with just source
and destination MAC address, the driver has to emulate it.

The hardware automatically creates entries entries for incoming flows, even
when they are bridged instead of routed, and reports when packets for these
flows have reached the minimum PPS rate for offloading.

After this happens, we look up the L2 flow offload entry based on the MAC
header and fill in the output routing information in the flow table.
The dynamically created per-flow entries are automatically removed when
either the hardware flowtable entry expires, is replaced, or if the offload
rule they belong to is removed

Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Felix Fietkau and committed by
David S. Miller
33fc42de 8ff25d37

+300 -47
+219 -22
drivers/net/ethernet/mediatek/mtk_ppe.c
··· 6 6 #include <linux/iopoll.h> 7 7 #include <linux/etherdevice.h> 8 8 #include <linux/platform_device.h> 9 + #include <linux/if_ether.h> 10 + #include <linux/if_vlan.h> 11 + #include <net/dsa.h> 9 12 #include "mtk_eth_soc.h" 10 13 #include "mtk_ppe.h" 11 14 #include "mtk_ppe_regs.h" 12 15 13 16 static DEFINE_SPINLOCK(ppe_lock); 17 + 18 + static const struct rhashtable_params mtk_flow_l2_ht_params = { 19 + .head_offset = offsetof(struct mtk_flow_entry, l2_node), 20 + .key_offset = offsetof(struct mtk_flow_entry, data.bridge), 21 + .key_len = offsetof(struct mtk_foe_bridge, key_end), 22 + .automatic_shrinking = true, 23 + }; 14 24 15 25 static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val) 16 26 { ··· 133 123 { 134 124 int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); 135 125 126 + if (type == MTK_PPE_PKT_TYPE_BRIDGE) 127 + return &entry->bridge.l2; 128 + 136 129 if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) 137 130 return &entry->ipv6.l2; 138 131 ··· 146 133 mtk_foe_entry_ib2(struct mtk_foe_entry *entry) 147 134 { 148 135 int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); 136 + 137 + if (type == MTK_PPE_PKT_TYPE_BRIDGE) 138 + return &entry->bridge.ib2; 149 139 150 140 if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) 151 141 return &entry->ipv6.ib2; ··· 184 168 if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T) 185 169 entry->ipv6.ports = ports_pad; 186 170 187 - if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { 171 + if (type == MTK_PPE_PKT_TYPE_BRIDGE) { 172 + ether_addr_copy(entry->bridge.src_mac, src_mac); 173 + ether_addr_copy(entry->bridge.dest_mac, dest_mac); 174 + entry->bridge.ib2 = val; 175 + l2 = &entry->bridge.l2; 176 + } else if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { 188 177 entry->ipv6.ib2 = val; 189 178 l2 = &entry->ipv6.l2; 190 179 } else { ··· 393 372 } 394 373 395 374 static void 375 + __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 376 + { 377 + struct hlist_head *head; 378 + struct hlist_node *tmp; 379 + 380 + if (entry->type == MTK_FLOW_TYPE_L2) { 381 + rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, 382 + mtk_flow_l2_ht_params); 383 + 384 + head = &entry->l2_flows; 385 + hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) 386 + __mtk_foe_entry_clear(ppe, entry); 387 + return; 388 + } 389 + 390 + hlist_del_init(&entry->list); 391 + if (entry->hash != 0xffff) { 392 + ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; 393 + ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, 394 + MTK_FOE_STATE_BIND); 395 + dma_wmb(); 396 + } 397 + entry->hash = 0xffff; 398 + 399 + if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) 400 + return; 401 + 402 + hlist_del_init(&entry->l2_data.list); 403 + kfree(entry); 404 + } 405 + 406 + static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) 407 + { 408 + u16 timestamp; 409 + u16 now; 410 + 411 + now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; 412 + timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; 413 + 414 + if (timestamp > now) 415 + return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; 416 + else 417 + return now - timestamp; 418 + } 419 + 420 + static void 421 + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 422 + { 423 + struct mtk_flow_entry *cur; 424 + struct mtk_foe_entry *hwe; 425 + struct hlist_node *tmp; 426 + int idle; 427 + 428 + idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); 429 + hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { 430 + int cur_idle; 431 + u32 ib1; 432 + 433 + hwe = &ppe->foe_table[cur->hash]; 434 + ib1 = READ_ONCE(hwe->ib1); 435 + 436 + if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { 437 + cur->hash = 0xffff; 438 + __mtk_foe_entry_clear(ppe, cur); 439 + continue; 440 + } 441 + 442 + cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); 443 + if (cur_idle >= idle) 444 + continue; 445 + 446 + idle = cur_idle; 447 + entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; 448 + entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; 449 + } 450 + } 451 + 452 + static void 396 453 mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 397 454 { 398 455 struct mtk_foe_entry *hwe; 399 456 struct mtk_foe_entry foe; 400 457 401 458 spin_lock_bh(&ppe_lock); 459 + 460 + if (entry->type == MTK_FLOW_TYPE_L2) { 461 + mtk_flow_entry_update_l2(ppe, entry); 462 + goto out; 463 + } 464 + 402 465 if (entry->hash == 0xffff) 403 466 goto out; 404 467 ··· 524 419 void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 525 420 { 526 421 spin_lock_bh(&ppe_lock); 527 - hlist_del_init(&entry->list); 528 - if (entry->hash != 0xffff) { 529 - ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; 530 - ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, 531 - MTK_FOE_STATE_BIND); 532 - dma_wmb(); 533 - } 534 - entry->hash = 0xffff; 422 + __mtk_foe_entry_clear(ppe, entry); 535 423 spin_unlock_bh(&ppe_lock); 424 + } 425 + 426 + static int 427 + mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 428 + { 429 + entry->type = MTK_FLOW_TYPE_L2; 430 + 431 + return rhashtable_insert_fast(&ppe->l2_flows, &entry->l2_node, 432 + mtk_flow_l2_ht_params); 536 433 } 537 434 538 435 int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 539 436 { 540 - u32 hash = mtk_ppe_hash_entry(&entry->data); 437 + int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); 438 + u32 hash; 541 439 440 + if (type == MTK_PPE_PKT_TYPE_BRIDGE) 441 + return mtk_foe_entry_commit_l2(ppe, entry); 442 + 443 + hash = mtk_ppe_hash_entry(&entry->data); 542 444 entry->hash = 0xffff; 543 445 spin_lock_bh(&ppe_lock); 544 446 hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); ··· 554 442 return 0; 555 443 } 556 444 445 + static void 446 + mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, 447 + u16 hash) 448 + { 449 + struct mtk_flow_entry *flow_info; 450 + struct mtk_foe_entry foe, *hwe; 451 + struct mtk_foe_mac_info *l2; 452 + u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; 453 + int type; 454 + 455 + flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), 456 + GFP_ATOMIC); 457 + if (!flow_info) 458 + return; 459 + 460 + flow_info->l2_data.base_flow = entry; 461 + flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; 462 + flow_info->hash = hash; 463 + hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]); 464 + hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); 465 + 466 + hwe = &ppe->foe_table[hash]; 467 + memcpy(&foe, hwe, sizeof(foe)); 468 + foe.ib1 &= ib1_mask; 469 + foe.ib1 |= entry->data.ib1 & ~ib1_mask; 470 + 471 + l2 = mtk_foe_entry_l2(&foe); 472 + memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); 473 + 474 + type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1); 475 + if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) 476 + memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); 477 + else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) 478 + l2->etype = ETH_P_IPV6; 479 + 480 + *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2; 481 + 482 + __mtk_foe_entry_commit(ppe, &foe, hash); 483 + } 484 + 557 485 void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) 558 486 { 559 487 struct hlist_head *head = &ppe->foe_flow[hash / 2]; 560 - struct mtk_flow_entry *entry; 561 488 struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; 489 + struct mtk_flow_entry *entry; 490 + struct mtk_foe_bridge key = {}; 491 + struct ethhdr *eh; 562 492 bool found = false; 563 - 564 - if (hlist_empty(head)) 565 - return; 493 + u8 *tag; 566 494 567 495 spin_lock_bh(&ppe_lock); 496 + 497 + if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) 498 + goto out; 499 + 568 500 hlist_for_each_entry(entry, head, list) { 501 + if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { 502 + if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == 503 + MTK_FOE_STATE_BIND)) 504 + continue; 505 + 506 + entry->hash = 0xffff; 507 + __mtk_foe_entry_clear(ppe, entry); 508 + continue; 509 + } 510 + 569 511 if (found || !mtk_flow_entry_match(entry, hwe)) { 570 512 if (entry->hash != 0xffff) 571 513 entry->hash = 0xffff; ··· 630 464 __mtk_foe_entry_commit(ppe, &entry->data, hash); 631 465 found = true; 632 466 } 467 + 468 + if (found) 469 + goto out; 470 + 471 + eh = eth_hdr(skb); 472 + ether_addr_copy(key.dest_mac, eh->h_dest); 473 + ether_addr_copy(key.src_mac, eh->h_source); 474 + tag = skb->data - 2; 475 + key.vlan = 0; 476 + switch (skb->protocol) { 477 + #if IS_ENABLED(CONFIG_NET_DSA) 478 + case htons(ETH_P_XDSA): 479 + if (!netdev_uses_dsa(skb->dev) || 480 + skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK) 481 + goto out; 482 + 483 + tag += 4; 484 + if (get_unaligned_be16(tag) != ETH_P_8021Q) 485 + break; 486 + 487 + fallthrough; 488 + #endif 489 + case htons(ETH_P_8021Q): 490 + key.vlan = get_unaligned_be16(tag + 2) & VLAN_VID_MASK; 491 + break; 492 + default: 493 + break; 494 + } 495 + 496 + entry = rhashtable_lookup_fast(&ppe->l2_flows, &key, mtk_flow_l2_ht_params); 497 + if (!entry) 498 + goto out; 499 + 500 + mtk_foe_entry_commit_subflow(ppe, entry, hash); 501 + 502 + out: 633 503 spin_unlock_bh(&ppe_lock); 634 504 } 635 505 636 506 int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 637 507 { 638 - u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; 639 - u16 timestamp; 640 - 641 508 mtk_flow_entry_update(ppe, entry); 642 - timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; 643 509 644 - if (timestamp > now) 645 - return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; 646 - else 647 - return now - timestamp; 510 + return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); 648 511 } 649 512 650 513 struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, ··· 686 491 ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); 687 492 if (!ppe) 688 493 return NULL; 494 + 495 + rhashtable_init(&ppe->l2_flows, &mtk_flow_l2_ht_params); 689 496 690 497 /* need to allocate a separate device, since it PPE DMA access is 691 498 * not coherent.
+33 -13
drivers/net/ethernet/mediatek/mtk_ppe.h
··· 6 6 7 7 #include <linux/kernel.h> 8 8 #include <linux/bitfield.h> 9 + #include <linux/rhashtable.h> 9 10 10 11 #define MTK_ETH_PPE_BASE 0xc00 11 12 ··· 85 84 u16 src_mac_lo; 86 85 }; 87 86 87 + /* software-only entry type */ 88 88 struct mtk_foe_bridge { 89 - u32 dest_mac_hi; 89 + u8 dest_mac[ETH_ALEN]; 90 + u8 src_mac[ETH_ALEN]; 91 + u16 vlan; 90 92 91 - u16 src_mac_lo; 92 - u16 dest_mac_lo; 93 - 94 - u32 src_mac_hi; 93 + struct {} key_end; 95 94 96 95 u32 ib2; 97 96 98 - u32 _rsv[5]; 99 - 100 - u32 udf_tsid; 101 97 struct mtk_foe_mac_info l2; 102 98 }; 103 99 ··· 233 235 MTK_PPE_CPU_REASON_INVALID = 0x1f, 234 236 }; 235 237 238 + enum { 239 + MTK_FLOW_TYPE_L4, 240 + MTK_FLOW_TYPE_L2, 241 + MTK_FLOW_TYPE_L2_SUBFLOW, 242 + }; 243 + 236 244 struct mtk_flow_entry { 237 - struct rhash_head node; 238 - struct hlist_node list; 239 - unsigned long cookie; 240 - struct mtk_foe_entry data; 241 - u16 hash; 245 + union { 246 + struct hlist_node list; 247 + struct { 248 + struct rhash_head l2_node; 249 + struct hlist_head l2_flows; 250 + }; 251 + }; 252 + u8 type; 242 253 s8 wed_index; 254 + u16 hash; 255 + union { 256 + struct mtk_foe_entry data; 257 + struct { 258 + struct mtk_flow_entry *base_flow; 259 + struct hlist_node list; 260 + struct {} end; 261 + } l2_data; 262 + }; 263 + struct rhash_head node; 264 + unsigned long cookie; 243 265 }; 244 266 245 267 struct mtk_ppe { ··· 273 255 274 256 u16 foe_check_time[MTK_PPE_ENTRIES]; 275 257 struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; 258 + 259 + struct rhashtable l2_flows; 276 260 277 261 void *acct_table; 278 262 };
+48 -12
drivers/net/ethernet/mediatek/mtk_ppe_offload.c
··· 31 31 __be16 src_port; 32 32 __be16 dst_port; 33 33 34 + u16 vlan_in; 35 + 34 36 struct { 35 37 u16 id; 36 38 __be16 proto; ··· 259 257 return -EOPNOTSUPP; 260 258 } 261 259 260 + switch (addr_type) { 261 + case 0: 262 + offload_type = MTK_PPE_PKT_TYPE_BRIDGE; 263 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { 264 + struct flow_match_eth_addrs match; 265 + 266 + flow_rule_match_eth_addrs(rule, &match); 267 + memcpy(data.eth.h_dest, match.key->dst, ETH_ALEN); 268 + memcpy(data.eth.h_source, match.key->src, ETH_ALEN); 269 + } else { 270 + return -EOPNOTSUPP; 271 + } 272 + 273 + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { 274 + struct flow_match_vlan match; 275 + 276 + flow_rule_match_vlan(rule, &match); 277 + 278 + if (match.key->vlan_tpid != cpu_to_be16(ETH_P_8021Q)) 279 + return -EOPNOTSUPP; 280 + 281 + data.vlan_in = match.key->vlan_id; 282 + } 283 + break; 284 + case FLOW_DISSECTOR_KEY_IPV4_ADDRS: 285 + offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; 286 + break; 287 + case FLOW_DISSECTOR_KEY_IPV6_ADDRS: 288 + offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; 289 + break; 290 + default: 291 + return -EOPNOTSUPP; 292 + } 293 + 262 294 flow_action_for_each(i, act, &rule->action) { 263 295 switch (act->id) { 264 296 case FLOW_ACTION_MANGLE: 297 + if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) 298 + return -EOPNOTSUPP; 265 299 if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH) 266 300 mtk_flow_offload_mangle_eth(act, &data.eth); 267 301 break; ··· 329 291 } 330 292 } 331 293 332 - switch (addr_type) { 333 - case FLOW_DISSECTOR_KEY_IPV4_ADDRS: 334 - offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; 335 - break; 336 - case FLOW_DISSECTOR_KEY_IPV6_ADDRS: 337 - offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; 338 - break; 339 - default: 340 - return -EOPNOTSUPP; 341 - } 342 - 343 294 if (!is_valid_ether_addr(data.eth.h_source) || 344 295 !is_valid_ether_addr(data.eth.h_dest)) 345 296 return -EINVAL; ··· 342 315 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { 343 316 struct flow_match_ports ports; 344 317 318 + if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) 319 + return -EOPNOTSUPP; 320 + 345 321 flow_rule_match_ports(rule, &ports); 346 322 data.src_port = ports.key->src; 347 323 data.dst_port = ports.key->dst; 348 - } else { 324 + } else if (offload_type != MTK_PPE_PKT_TYPE_BRIDGE) { 349 325 return -EOPNOTSUPP; 350 326 } 351 327 ··· 378 348 if (act->id != FLOW_ACTION_MANGLE) 379 349 continue; 380 350 351 + if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) 352 + return -EOPNOTSUPP; 353 + 381 354 switch (act->mangle.htype) { 382 355 case FLOW_ACT_MANGLE_HDR_TYPE_TCP: 383 356 case FLOW_ACT_MANGLE_HDR_TYPE_UDP: ··· 405 372 if (err) 406 373 return err; 407 374 } 375 + 376 + if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) 377 + foe.bridge.vlan = data.vlan_in; 408 378 409 379 if (data.vlan.num == 1) { 410 380 if (data.vlan.proto != htons(ETH_P_8021Q))