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 'add-flow-director-for-txgbe'

Jiawen Wu says:

====================
add flow director for txgbe

Add flow director support for Wangxun 10Gb NICs.

v2 -> v3: https://lore.kernel.org/all/20240605020852.24144-1-jiawenwu@trustnetic.com/
- Wrap the code at 80 chars where possible. (Jakub Kicinski)
- Add function description address on kernel-doc. (Jakub Kicinski)
- Correct return code. (Simon Horman)
- Remove redundant size check. (Hariprasad Kelam)

v1 -> v2: https://lore.kernel.org/all/20240529093821.27108-1-jiawenwu@trustnetic.com/
- Fix build warnings reported by kernel test robot.
====================

Link: https://lore.kernel.org/r/20240618101609.3580-1-jiawenwu@trustnetic.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+1436 -12
+35 -4
drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
··· 43 43 WX_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed), 44 44 }; 45 45 46 + static const struct wx_stats wx_gstrings_fdir_stats[] = { 47 + WX_STAT("fdir_match", stats.fdirmatch), 48 + WX_STAT("fdir_miss", stats.fdirmiss), 49 + }; 50 + 46 51 /* drivers allocates num_tx_queues and num_rx_queues symmetrically so 47 52 * we set the num_rx_queues to evaluate to num_tx_queues. This is 48 53 * used because we do not have a good way to get the max number of ··· 60 55 (WX_NUM_TX_QUEUES + WX_NUM_RX_QUEUES) * \ 61 56 (sizeof(struct wx_queue_stats) / sizeof(u64))) 62 57 #define WX_GLOBAL_STATS_LEN ARRAY_SIZE(wx_gstrings_stats) 58 + #define WX_FDIR_STATS_LEN ARRAY_SIZE(wx_gstrings_fdir_stats) 63 59 #define WX_STATS_LEN (WX_GLOBAL_STATS_LEN + WX_QUEUE_STATS_LEN) 64 60 65 61 int wx_get_sset_count(struct net_device *netdev, int sset) 66 62 { 63 + struct wx *wx = netdev_priv(netdev); 64 + 67 65 switch (sset) { 68 66 case ETH_SS_STATS: 69 - return WX_STATS_LEN; 67 + return (wx->mac.type == wx_mac_sp) ? 68 + WX_STATS_LEN + WX_FDIR_STATS_LEN : WX_STATS_LEN; 70 69 default: 71 70 return -EOPNOTSUPP; 72 71 } ··· 79 70 80 71 void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 81 72 { 73 + struct wx *wx = netdev_priv(netdev); 82 74 u8 *p = data; 83 75 int i; 84 76 ··· 87 77 case ETH_SS_STATS: 88 78 for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) 89 79 ethtool_puts(&p, wx_gstrings_stats[i].stat_string); 80 + if (wx->mac.type == wx_mac_sp) { 81 + for (i = 0; i < WX_FDIR_STATS_LEN; i++) 82 + ethtool_puts(&p, wx_gstrings_fdir_stats[i].stat_string); 83 + } 90 84 for (i = 0; i < netdev->num_tx_queues; i++) { 91 85 ethtool_sprintf(&p, "tx_queue_%u_packets", i); 92 86 ethtool_sprintf(&p, "tx_queue_%u_bytes", i); ··· 110 96 struct wx *wx = netdev_priv(netdev); 111 97 struct wx_ring *ring; 112 98 unsigned int start; 113 - int i, j; 99 + int i, j, k; 114 100 char *p; 115 101 116 102 wx_update_stats(wx); ··· 119 105 p = (char *)wx + wx_gstrings_stats[i].stat_offset; 120 106 data[i] = (wx_gstrings_stats[i].sizeof_stat == 121 107 sizeof(u64)) ? *(u64 *)p : *(u32 *)p; 108 + } 109 + 110 + if (wx->mac.type == wx_mac_sp) { 111 + for (k = 0; k < WX_FDIR_STATS_LEN; k++) { 112 + p = (char *)wx + wx_gstrings_fdir_stats[k].stat_offset; 113 + data[i++] = *(u64 *)p; 114 + } 122 115 } 123 116 124 117 for (j = 0; j < netdev->num_tx_queues; j++) { ··· 193 172 194 173 void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) 195 174 { 175 + unsigned int stats_len = WX_STATS_LEN; 196 176 struct wx *wx = netdev_priv(netdev); 177 + 178 + if (wx->mac.type == wx_mac_sp) 179 + stats_len += WX_FDIR_STATS_LEN; 197 180 198 181 strscpy(info->driver, wx->driver_name, sizeof(info->driver)); 199 182 strscpy(info->fw_version, wx->eeprom_id, sizeof(info->fw_version)); 200 183 strscpy(info->bus_info, pci_name(wx->pdev), sizeof(info->bus_info)); 201 184 if (wx->num_tx_queues <= WX_NUM_TX_QUEUES) { 202 - info->n_stats = WX_STATS_LEN - 185 + info->n_stats = stats_len - 203 186 (WX_NUM_TX_QUEUES - wx->num_tx_queues) * 204 187 (sizeof(struct wx_queue_stats) / sizeof(u64)) * 2; 205 188 } else { 206 - info->n_stats = WX_STATS_LEN; 189 + info->n_stats = stats_len; 207 190 } 208 191 } 209 192 EXPORT_SYMBOL(wx_get_drvinfo); ··· 408 383 409 384 /* record RSS queues */ 410 385 ch->combined_count = wx->ring_feature[RING_F_RSS].indices; 386 + 387 + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) 388 + ch->combined_count = wx->ring_feature[RING_F_FDIR].indices; 411 389 } 412 390 EXPORT_SYMBOL(wx_get_channels); 413 391 ··· 427 399 /* verify the number of channels does not exceed hardware limits */ 428 400 if (count > wx_max_channels(wx)) 429 401 return -EINVAL; 402 + 403 + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) 404 + wx->ring_feature[RING_F_FDIR].limit = count; 430 405 431 406 wx->ring_feature[RING_F_RSS].limit = count; 432 407
+28 -4
drivers/net/ethernet/wangxun/libwx/wx_hw.c
··· 1147 1147 static void wx_set_rxpba(struct wx *wx) 1148 1148 { 1149 1149 u32 rxpktsize, txpktsize, txpbthresh; 1150 + u32 pbsize = wx->mac.rx_pb_size; 1150 1151 1151 - rxpktsize = wx->mac.rx_pb_size << WX_RDB_PB_SZ_SHIFT; 1152 + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) { 1153 + if (test_bit(WX_FLAG_FDIR_HASH, wx->flags) || 1154 + test_bit(WX_FLAG_FDIR_PERFECT, wx->flags)) 1155 + pbsize -= 64; /* Default 64KB */ 1156 + } 1157 + 1158 + rxpktsize = pbsize << WX_RDB_PB_SZ_SHIFT; 1152 1159 wr32(wx, WX_RDB_PB_SZ(0), rxpktsize); 1153 1160 1154 1161 /* Only support an equally distributed Tx packet buffer strategy. */ ··· 1268 1261 * Stops the receive data path and waits for the HW to internally empty 1269 1262 * the Rx security block 1270 1263 **/ 1271 - static int wx_disable_sec_rx_path(struct wx *wx) 1264 + int wx_disable_sec_rx_path(struct wx *wx) 1272 1265 { 1273 1266 u32 secrx; 1274 1267 ··· 1278 1271 return read_poll_timeout(rd32, secrx, secrx & WX_RSC_ST_RSEC_RDY, 1279 1272 1000, 40000, false, wx, WX_RSC_ST); 1280 1273 } 1274 + EXPORT_SYMBOL(wx_disable_sec_rx_path); 1281 1275 1282 1276 /** 1283 1277 * wx_enable_sec_rx_path - Enables the receive data path ··· 1286 1278 * 1287 1279 * Enables the receive data path. 1288 1280 **/ 1289 - static void wx_enable_sec_rx_path(struct wx *wx) 1281 + void wx_enable_sec_rx_path(struct wx *wx) 1290 1282 { 1291 1283 wr32m(wx, WX_RSC_CTL, WX_RSC_CTL_RX_DIS, 0); 1292 1284 WX_WRITE_FLUSH(wx); 1293 1285 } 1286 + EXPORT_SYMBOL(wx_enable_sec_rx_path); 1294 1287 1295 1288 static void wx_vlan_strip_control(struct wx *wx, bool enable) 1296 1289 { ··· 1507 1498 if (ring->count < WX_MAX_TXD) 1508 1499 txdctl |= ring->count / 128 << WX_PX_TR_CFG_TR_SIZE_SHIFT; 1509 1500 txdctl |= 0x20 << WX_PX_TR_CFG_WTHRESH_SHIFT; 1501 + 1502 + ring->atr_count = 0; 1503 + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags) && 1504 + test_bit(WX_FLAG_FDIR_HASH, wx->flags)) 1505 + ring->atr_sample_rate = wx->atr_sample_rate; 1506 + else 1507 + ring->atr_sample_rate = 0; 1510 1508 1511 1509 /* reinitialize tx_buffer_info */ 1512 1510 memset(ring->tx_buffer_info, 0, ··· 1748 1732 1749 1733 wx_set_rx_mode(wx->netdev); 1750 1734 wx_restore_vlan(wx); 1751 - wx_enable_sec_rx_path(wx); 1735 + 1736 + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) 1737 + wx->configure_fdir(wx); 1752 1738 1753 1739 wx_configure_tx(wx); 1754 1740 wx_configure_rx(wx); ··· 1977 1959 } 1978 1960 1979 1961 bitmap_zero(wx->state, WX_STATE_NBITS); 1962 + bitmap_zero(wx->flags, WX_PF_FLAGS_NBITS); 1980 1963 1981 1964 return 0; 1982 1965 } ··· 2351 2332 hwstats->o2bspc += rd32(wx, WX_MNG_OS2BMC_CNT); 2352 2333 hwstats->b2ogprc += rd32(wx, WX_RDM_BMC2OS_CNT); 2353 2334 hwstats->rdmdrop += rd32(wx, WX_RDM_DRP_PKT); 2335 + 2336 + if (wx->mac.type == wx_mac_sp) { 2337 + hwstats->fdirmatch += rd32(wx, WX_RDB_FDIR_MATCH); 2338 + hwstats->fdirmiss += rd32(wx, WX_RDB_FDIR_MISS); 2339 + } 2354 2340 2355 2341 for (i = 0; i < wx->mac.max_rx_queues; i++) 2356 2342 hwstats->qmprc += rd32(wx, WX_PX_MPRC(i));
+2
drivers/net/ethernet/wangxun/libwx/wx_hw.h
··· 28 28 void wx_flush_sw_mac_table(struct wx *wx); 29 29 int wx_set_mac(struct net_device *netdev, void *p); 30 30 void wx_disable_rx(struct wx *wx); 31 + int wx_disable_sec_rx_path(struct wx *wx); 32 + void wx_enable_sec_rx_path(struct wx *wx); 31 33 void wx_set_rx_mode(struct net_device *netdev); 32 34 int wx_change_mtu(struct net_device *netdev, int new_mtu); 33 35 void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring);
+59 -3
drivers/net/ethernet/wangxun/libwx/wx_lib.c
··· 148 148 [0xFD] = WX_PTT(IP, IPV6, IGMV, IPV6, SCTP, PAY4), 149 149 }; 150 150 151 - static struct wx_dec_ptype wx_decode_ptype(const u8 ptype) 151 + struct wx_dec_ptype wx_decode_ptype(const u8 ptype) 152 152 { 153 153 return wx_ptype_lookup[ptype]; 154 154 } 155 + EXPORT_SYMBOL(wx_decode_ptype); 155 156 156 157 /* wx_test_staterr - tests bits in Rx descriptor status and error fields */ 157 158 static __le32 wx_test_staterr(union wx_rx_desc *rx_desc, ··· 1454 1453 static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb, 1455 1454 struct wx_ring *tx_ring) 1456 1455 { 1456 + struct wx *wx = netdev_priv(tx_ring->netdev); 1457 1457 u16 count = TXD_USE_COUNT(skb_headlen(skb)); 1458 1458 struct wx_tx_buffer *first; 1459 1459 u8 hdr_len = 0, ptype; ··· 1500 1498 goto out_drop; 1501 1499 else if (!tso) 1502 1500 wx_tx_csum(tx_ring, first, ptype); 1501 + 1502 + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags) && tx_ring->atr_sample_rate) 1503 + wx->atr(tx_ring, first, ptype); 1504 + 1503 1505 wx_tx_map(tx_ring, first, hdr_len); 1504 1506 1505 1507 return NETDEV_TX_OK; ··· 1580 1574 f = &wx->ring_feature[RING_F_RSS]; 1581 1575 f->indices = f->limit; 1582 1576 1583 - wx->num_rx_queues = f->limit; 1584 - wx->num_tx_queues = f->limit; 1577 + if (!(test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags))) 1578 + goto out; 1579 + 1580 + clear_bit(WX_FLAG_FDIR_HASH, wx->flags); 1581 + 1582 + /* Use Flow Director in addition to RSS to ensure the best 1583 + * distribution of flows across cores, even when an FDIR flow 1584 + * isn't matched. 1585 + */ 1586 + if (f->indices > 1) { 1587 + f = &wx->ring_feature[RING_F_FDIR]; 1588 + 1589 + f->indices = f->limit; 1590 + 1591 + if (!(test_bit(WX_FLAG_FDIR_PERFECT, wx->flags))) 1592 + set_bit(WX_FLAG_FDIR_HASH, wx->flags); 1593 + } 1594 + 1595 + out: 1596 + wx->num_rx_queues = f->indices; 1597 + wx->num_tx_queues = f->indices; 1585 1598 } 1586 1599 1587 1600 static void wx_set_num_queues(struct wx *wx) ··· 2705 2680 { 2706 2681 netdev_features_t changed = netdev->features ^ features; 2707 2682 struct wx *wx = netdev_priv(netdev); 2683 + bool need_reset = false; 2708 2684 2709 2685 if (features & NETIF_F_RXHASH) { 2710 2686 wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, ··· 2722 2696 wx->do_reset(netdev); 2723 2697 else if (changed & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER)) 2724 2698 wx_set_rx_mode(netdev); 2699 + 2700 + if (!(test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags))) 2701 + return 0; 2702 + 2703 + /* Check if Flow Director n-tuple support was enabled or disabled. If 2704 + * the state changed, we need to reset. 2705 + */ 2706 + switch (features & NETIF_F_NTUPLE) { 2707 + case NETIF_F_NTUPLE: 2708 + /* turn off ATR, enable perfect filters and reset */ 2709 + if (!(test_and_set_bit(WX_FLAG_FDIR_PERFECT, wx->flags))) 2710 + need_reset = true; 2711 + 2712 + clear_bit(WX_FLAG_FDIR_HASH, wx->flags); 2713 + break; 2714 + default: 2715 + /* turn off perfect filters, enable ATR and reset */ 2716 + if (test_and_clear_bit(WX_FLAG_FDIR_PERFECT, wx->flags)) 2717 + need_reset = true; 2718 + 2719 + /* We cannot enable ATR if RSS is disabled */ 2720 + if (wx->ring_feature[RING_F_RSS].limit <= 1) 2721 + break; 2722 + 2723 + set_bit(WX_FLAG_FDIR_HASH, wx->flags); 2724 + break; 2725 + } 2726 + 2727 + if (need_reset) 2728 + wx->do_reset(netdev); 2725 2729 2726 2730 return 0; 2727 2731 }
+1
drivers/net/ethernet/wangxun/libwx/wx_lib.h
··· 7 7 #ifndef _WX_LIB_H_ 8 8 #define _WX_LIB_H_ 9 9 10 + struct wx_dec_ptype wx_decode_ptype(const u8 ptype); 10 11 void wx_alloc_rx_buffers(struct wx_ring *rx_ring, u16 cleaned_count); 11 12 u16 wx_desc_unused(struct wx_ring *ring); 12 13 netdev_tx_t wx_xmit_frame(struct sk_buff *skb,
+55 -1
drivers/net/ethernet/wangxun/libwx/wx_type.h
··· 157 157 #define WX_RDB_RA_CTL_RSS_IPV6_TCP BIT(21) 158 158 #define WX_RDB_RA_CTL_RSS_IPV4_UDP BIT(22) 159 159 #define WX_RDB_RA_CTL_RSS_IPV6_UDP BIT(23) 160 + #define WX_RDB_FDIR_MATCH 0x19558 161 + #define WX_RDB_FDIR_MISS 0x1955C 160 162 161 163 /******************************* PSR Registers *******************************/ 162 164 /* psr control */ ··· 505 503 #define WX_PTYPE_TYP_TCP 0x04 506 504 #define WX_PTYPE_TYP_SCTP 0x05 507 505 506 + /* Packet type non-ip values */ 507 + enum wx_l2_ptypes { 508 + WX_PTYPE_L2_ABORTED = (WX_PTYPE_PKT_MAC), 509 + WX_PTYPE_L2_MAC = (WX_PTYPE_PKT_MAC | WX_PTYPE_TYP_MAC), 510 + 511 + WX_PTYPE_L2_IPV4_FRAG = (WX_PTYPE_PKT_IP | WX_PTYPE_TYP_IPFRAG), 512 + WX_PTYPE_L2_IPV4 = (WX_PTYPE_PKT_IP | WX_PTYPE_TYP_IP), 513 + WX_PTYPE_L2_IPV4_UDP = (WX_PTYPE_PKT_IP | WX_PTYPE_TYP_UDP), 514 + WX_PTYPE_L2_IPV4_TCP = (WX_PTYPE_PKT_IP | WX_PTYPE_TYP_TCP), 515 + WX_PTYPE_L2_IPV4_SCTP = (WX_PTYPE_PKT_IP | WX_PTYPE_TYP_SCTP), 516 + WX_PTYPE_L2_IPV6_FRAG = (WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6 | 517 + WX_PTYPE_TYP_IPFRAG), 518 + WX_PTYPE_L2_IPV6 = (WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6 | 519 + WX_PTYPE_TYP_IP), 520 + WX_PTYPE_L2_IPV6_UDP = (WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6 | 521 + WX_PTYPE_TYP_UDP), 522 + WX_PTYPE_L2_IPV6_TCP = (WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6 | 523 + WX_PTYPE_TYP_TCP), 524 + WX_PTYPE_L2_IPV6_SCTP = (WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6 | 525 + WX_PTYPE_TYP_SCTP), 526 + 527 + WX_PTYPE_L2_TUN4_MAC = (WX_PTYPE_TUN_IPV4 | WX_PTYPE_PKT_IGM), 528 + WX_PTYPE_L2_TUN6_MAC = (WX_PTYPE_TUN_IPV6 | WX_PTYPE_PKT_IGM), 529 + }; 530 + 531 + #define WX_PTYPE_PKT(_pt) ((_pt) & 0x30) 532 + #define WX_PTYPE_TYPL4(_pt) ((_pt) & 0x07) 533 + 508 534 #define WX_RXD_PKTTYPE(_rxd) \ 509 535 ((le32_to_cpu((_rxd)->wb.lower.lo_dword.data) >> 9) & 0xFF) 510 536 #define WX_RXD_IPV6EX(_rxd) \ ··· 582 552 WX_TX_FLAGS_OUTER_IPV4 = 0x100, 583 553 WX_TX_FLAGS_LINKSEC = 0x200, 584 554 WX_TX_FLAGS_IPSEC = 0x400, 555 + 556 + /* software defined flags */ 557 + WX_TX_FLAGS_SW_VLAN = 0x40, 585 558 }; 586 559 587 560 /* VLAN info */ ··· 933 900 */ 934 901 u16 next_to_use; 935 902 u16 next_to_clean; 936 - u16 next_to_alloc; 903 + union { 904 + u16 next_to_alloc; 905 + struct { 906 + u8 atr_sample_rate; 907 + u8 atr_count; 908 + }; 909 + }; 937 910 938 911 struct wx_queue_stats stats; 939 912 struct u64_stats_sync syncp; ··· 978 939 enum wx_ring_f_enum { 979 940 RING_F_NONE = 0, 980 941 RING_F_RSS, 942 + RING_F_FDIR, 981 943 RING_F_ARRAY_SIZE /* must be last in enum set */ 982 944 }; 983 945 ··· 1020 980 u64 crcerrs; 1021 981 u64 rlec; 1022 982 u64 qmprc; 983 + u64 fdirmatch; 984 + u64 fdirmiss; 1023 985 }; 1024 986 1025 987 enum wx_state { 1026 988 WX_STATE_RESETTING, 1027 989 WX_STATE_NBITS, /* must be last */ 1028 990 }; 991 + 992 + enum wx_pf_flags { 993 + WX_FLAG_FDIR_CAPABLE, 994 + WX_FLAG_FDIR_HASH, 995 + WX_FLAG_FDIR_PERFECT, 996 + WX_PF_FLAGS_NBITS /* must be last */ 997 + }; 998 + 1029 999 struct wx { 1030 1000 unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; 1031 1001 DECLARE_BITMAP(state, WX_STATE_NBITS); 1002 + DECLARE_BITMAP(flags, WX_PF_FLAGS_NBITS); 1032 1003 1033 1004 void *priv; 1034 1005 u8 __iomem *hw_addr; ··· 1128 1077 u64 hw_csum_rx_error; 1129 1078 u64 alloc_rx_buff_failed; 1130 1079 1080 + u32 atr_sample_rate; 1081 + void (*atr)(struct wx_ring *ring, struct wx_tx_buffer *first, u8 ptype); 1082 + void (*configure_fdir)(struct wx *wx); 1131 1083 void (*do_reset)(struct net_device *netdev); 1132 1084 }; 1133 1085
+1
drivers/net/ethernet/wangxun/txgbe/Makefile
··· 10 10 txgbe_hw.o \ 11 11 txgbe_phy.o \ 12 12 txgbe_irq.o \ 13 + txgbe_fdir.o \ 13 14 txgbe_ethtool.o
+427
drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
··· 9 9 #include "../libwx/wx_type.h" 10 10 #include "../libwx/wx_lib.h" 11 11 #include "txgbe_type.h" 12 + #include "txgbe_fdir.h" 12 13 #include "txgbe_ethtool.h" 13 14 14 15 static int txgbe_set_ringparam(struct net_device *netdev, ··· 80 79 return txgbe_setup_tc(dev, netdev_get_num_tc(dev)); 81 80 } 82 81 82 + static int txgbe_get_ethtool_fdir_entry(struct txgbe *txgbe, 83 + struct ethtool_rxnfc *cmd) 84 + { 85 + struct ethtool_rx_flow_spec *fsp = 86 + (struct ethtool_rx_flow_spec *)&cmd->fs; 87 + union txgbe_atr_input *mask = &txgbe->fdir_mask; 88 + struct txgbe_fdir_filter *rule = NULL; 89 + struct hlist_node *node; 90 + 91 + /* report total rule count */ 92 + cmd->data = (1024 << TXGBE_FDIR_PBALLOC_64K) - 2; 93 + 94 + hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list, 95 + fdir_node) { 96 + if (fsp->location <= rule->sw_idx) 97 + break; 98 + } 99 + 100 + if (!rule || fsp->location != rule->sw_idx) 101 + return -EINVAL; 102 + 103 + /* set flow type field */ 104 + switch (rule->filter.formatted.flow_type) { 105 + case TXGBE_ATR_FLOW_TYPE_TCPV4: 106 + fsp->flow_type = TCP_V4_FLOW; 107 + break; 108 + case TXGBE_ATR_FLOW_TYPE_UDPV4: 109 + fsp->flow_type = UDP_V4_FLOW; 110 + break; 111 + case TXGBE_ATR_FLOW_TYPE_SCTPV4: 112 + fsp->flow_type = SCTP_V4_FLOW; 113 + break; 114 + case TXGBE_ATR_FLOW_TYPE_IPV4: 115 + fsp->flow_type = IP_USER_FLOW; 116 + fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; 117 + fsp->h_u.usr_ip4_spec.proto = 0; 118 + fsp->m_u.usr_ip4_spec.proto = 0; 119 + break; 120 + default: 121 + return -EINVAL; 122 + } 123 + 124 + fsp->h_u.tcp_ip4_spec.psrc = rule->filter.formatted.src_port; 125 + fsp->m_u.tcp_ip4_spec.psrc = mask->formatted.src_port; 126 + fsp->h_u.tcp_ip4_spec.pdst = rule->filter.formatted.dst_port; 127 + fsp->m_u.tcp_ip4_spec.pdst = mask->formatted.dst_port; 128 + fsp->h_u.tcp_ip4_spec.ip4src = rule->filter.formatted.src_ip[0]; 129 + fsp->m_u.tcp_ip4_spec.ip4src = mask->formatted.src_ip[0]; 130 + fsp->h_u.tcp_ip4_spec.ip4dst = rule->filter.formatted.dst_ip[0]; 131 + fsp->m_u.tcp_ip4_spec.ip4dst = mask->formatted.dst_ip[0]; 132 + fsp->h_ext.vlan_etype = rule->filter.formatted.flex_bytes; 133 + fsp->m_ext.vlan_etype = mask->formatted.flex_bytes; 134 + fsp->h_ext.data[1] = htonl(rule->filter.formatted.vm_pool); 135 + fsp->m_ext.data[1] = htonl(mask->formatted.vm_pool); 136 + fsp->flow_type |= FLOW_EXT; 137 + 138 + /* record action */ 139 + if (rule->action == TXGBE_RDB_FDIR_DROP_QUEUE) 140 + fsp->ring_cookie = RX_CLS_FLOW_DISC; 141 + else 142 + fsp->ring_cookie = rule->action; 143 + 144 + return 0; 145 + } 146 + 147 + static int txgbe_get_ethtool_fdir_all(struct txgbe *txgbe, 148 + struct ethtool_rxnfc *cmd, 149 + u32 *rule_locs) 150 + { 151 + struct txgbe_fdir_filter *rule; 152 + struct hlist_node *node; 153 + int cnt = 0; 154 + 155 + /* report total rule count */ 156 + cmd->data = (1024 << TXGBE_FDIR_PBALLOC_64K) - 2; 157 + 158 + hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list, 159 + fdir_node) { 160 + if (cnt == cmd->rule_cnt) 161 + return -EMSGSIZE; 162 + rule_locs[cnt] = rule->sw_idx; 163 + cnt++; 164 + } 165 + 166 + cmd->rule_cnt = cnt; 167 + 168 + return 0; 169 + } 170 + 171 + static int txgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, 172 + u32 *rule_locs) 173 + { 174 + struct wx *wx = netdev_priv(dev); 175 + struct txgbe *txgbe = wx->priv; 176 + int ret = -EOPNOTSUPP; 177 + 178 + switch (cmd->cmd) { 179 + case ETHTOOL_GRXRINGS: 180 + cmd->data = wx->num_rx_queues; 181 + ret = 0; 182 + break; 183 + case ETHTOOL_GRXCLSRLCNT: 184 + cmd->rule_cnt = txgbe->fdir_filter_count; 185 + ret = 0; 186 + break; 187 + case ETHTOOL_GRXCLSRULE: 188 + ret = txgbe_get_ethtool_fdir_entry(txgbe, cmd); 189 + break; 190 + case ETHTOOL_GRXCLSRLALL: 191 + ret = txgbe_get_ethtool_fdir_all(txgbe, cmd, (u32 *)rule_locs); 192 + break; 193 + default: 194 + break; 195 + } 196 + 197 + return ret; 198 + } 199 + 200 + static int txgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp, 201 + u8 *flow_type) 202 + { 203 + switch (fsp->flow_type & ~FLOW_EXT) { 204 + case TCP_V4_FLOW: 205 + *flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4; 206 + break; 207 + case UDP_V4_FLOW: 208 + *flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4; 209 + break; 210 + case SCTP_V4_FLOW: 211 + *flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4; 212 + break; 213 + case IP_USER_FLOW: 214 + switch (fsp->h_u.usr_ip4_spec.proto) { 215 + case IPPROTO_TCP: 216 + *flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4; 217 + break; 218 + case IPPROTO_UDP: 219 + *flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4; 220 + break; 221 + case IPPROTO_SCTP: 222 + *flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4; 223 + break; 224 + case 0: 225 + if (!fsp->m_u.usr_ip4_spec.proto) { 226 + *flow_type = TXGBE_ATR_FLOW_TYPE_IPV4; 227 + break; 228 + } 229 + fallthrough; 230 + default: 231 + return -EINVAL; 232 + } 233 + break; 234 + default: 235 + return -EINVAL; 236 + } 237 + 238 + return 0; 239 + } 240 + 241 + static bool txgbe_match_ethtool_fdir_entry(struct txgbe *txgbe, 242 + struct txgbe_fdir_filter *input) 243 + { 244 + struct txgbe_fdir_filter *rule = NULL; 245 + struct hlist_node *node2; 246 + 247 + hlist_for_each_entry_safe(rule, node2, &txgbe->fdir_filter_list, 248 + fdir_node) { 249 + if (rule->filter.formatted.bkt_hash == 250 + input->filter.formatted.bkt_hash && 251 + rule->action == input->action) { 252 + wx_dbg(txgbe->wx, "FDIR entry already exist\n"); 253 + return true; 254 + } 255 + } 256 + return false; 257 + } 258 + 259 + static int txgbe_update_ethtool_fdir_entry(struct txgbe *txgbe, 260 + struct txgbe_fdir_filter *input, 261 + u16 sw_idx) 262 + { 263 + struct hlist_node *node = NULL, *parent = NULL; 264 + struct txgbe_fdir_filter *rule; 265 + struct wx *wx = txgbe->wx; 266 + bool deleted = false; 267 + int err; 268 + 269 + hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list, 270 + fdir_node) { 271 + /* hash found, or no matching entry */ 272 + if (rule->sw_idx >= sw_idx) 273 + break; 274 + parent = node; 275 + } 276 + 277 + /* if there is an old rule occupying our place remove it */ 278 + if (rule && rule->sw_idx == sw_idx) { 279 + /* hardware filters are only configured when interface is up, 280 + * and we should not issue filter commands while the interface 281 + * is down 282 + */ 283 + if (netif_running(wx->netdev) && 284 + (!input || rule->filter.formatted.bkt_hash != 285 + input->filter.formatted.bkt_hash)) { 286 + err = txgbe_fdir_erase_perfect_filter(wx, 287 + &rule->filter, 288 + sw_idx); 289 + if (err) 290 + return -EINVAL; 291 + } 292 + 293 + hlist_del(&rule->fdir_node); 294 + kfree(rule); 295 + txgbe->fdir_filter_count--; 296 + deleted = true; 297 + } 298 + 299 + /* If we weren't given an input, then this was a request to delete a 300 + * filter. We should return -EINVAL if the filter wasn't found, but 301 + * return 0 if the rule was successfully deleted. 302 + */ 303 + if (!input) 304 + return deleted ? 0 : -EINVAL; 305 + 306 + /* initialize node and set software index */ 307 + INIT_HLIST_NODE(&input->fdir_node); 308 + 309 + /* add filter to the list */ 310 + if (parent) 311 + hlist_add_behind(&input->fdir_node, parent); 312 + else 313 + hlist_add_head(&input->fdir_node, 314 + &txgbe->fdir_filter_list); 315 + 316 + /* update counts */ 317 + txgbe->fdir_filter_count++; 318 + 319 + return 0; 320 + } 321 + 322 + static int txgbe_add_ethtool_fdir_entry(struct txgbe *txgbe, 323 + struct ethtool_rxnfc *cmd) 324 + { 325 + struct ethtool_rx_flow_spec *fsp = 326 + (struct ethtool_rx_flow_spec *)&cmd->fs; 327 + struct txgbe_fdir_filter *input; 328 + union txgbe_atr_input mask; 329 + struct wx *wx = txgbe->wx; 330 + int err = -EINVAL; 331 + u16 ptype = 0; 332 + u8 queue; 333 + 334 + if (!(test_bit(WX_FLAG_FDIR_PERFECT, wx->flags))) 335 + return -EOPNOTSUPP; 336 + 337 + /* ring_cookie is a masked into a set of queues and txgbe pools or 338 + * we use drop index 339 + */ 340 + if (fsp->ring_cookie == RX_CLS_FLOW_DISC) { 341 + queue = TXGBE_RDB_FDIR_DROP_QUEUE; 342 + } else { 343 + u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie); 344 + 345 + if (ring >= wx->num_rx_queues) 346 + return -EINVAL; 347 + 348 + /* Map the ring onto the absolute queue index */ 349 + queue = wx->rx_ring[ring]->reg_idx; 350 + } 351 + 352 + /* Don't allow indexes to exist outside of available space */ 353 + if (fsp->location >= ((1024 << TXGBE_FDIR_PBALLOC_64K) - 2)) { 354 + wx_err(wx, "Location out of range\n"); 355 + return -EINVAL; 356 + } 357 + 358 + input = kzalloc(sizeof(*input), GFP_ATOMIC); 359 + if (!input) 360 + return -ENOMEM; 361 + 362 + memset(&mask, 0, sizeof(union txgbe_atr_input)); 363 + 364 + /* set SW index */ 365 + input->sw_idx = fsp->location; 366 + 367 + /* record flow type */ 368 + if (txgbe_flowspec_to_flow_type(fsp, 369 + &input->filter.formatted.flow_type)) { 370 + wx_err(wx, "Unrecognized flow type\n"); 371 + goto err_out; 372 + } 373 + 374 + mask.formatted.flow_type = TXGBE_ATR_L4TYPE_IPV6_MASK | 375 + TXGBE_ATR_L4TYPE_MASK; 376 + 377 + if (input->filter.formatted.flow_type == TXGBE_ATR_FLOW_TYPE_IPV4) 378 + mask.formatted.flow_type &= TXGBE_ATR_L4TYPE_IPV6_MASK; 379 + 380 + /* Copy input into formatted structures */ 381 + input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src; 382 + mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src; 383 + input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst; 384 + mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst; 385 + input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc; 386 + mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc; 387 + input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst; 388 + mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst; 389 + 390 + if (fsp->flow_type & FLOW_EXT) { 391 + input->filter.formatted.vm_pool = 392 + (unsigned char)ntohl(fsp->h_ext.data[1]); 393 + mask.formatted.vm_pool = 394 + (unsigned char)ntohl(fsp->m_ext.data[1]); 395 + input->filter.formatted.flex_bytes = 396 + fsp->h_ext.vlan_etype; 397 + mask.formatted.flex_bytes = fsp->m_ext.vlan_etype; 398 + } 399 + 400 + switch (input->filter.formatted.flow_type) { 401 + case TXGBE_ATR_FLOW_TYPE_TCPV4: 402 + ptype = WX_PTYPE_L2_IPV4_TCP; 403 + break; 404 + case TXGBE_ATR_FLOW_TYPE_UDPV4: 405 + ptype = WX_PTYPE_L2_IPV4_UDP; 406 + break; 407 + case TXGBE_ATR_FLOW_TYPE_SCTPV4: 408 + ptype = WX_PTYPE_L2_IPV4_SCTP; 409 + break; 410 + case TXGBE_ATR_FLOW_TYPE_IPV4: 411 + ptype = WX_PTYPE_L2_IPV4; 412 + break; 413 + default: 414 + break; 415 + } 416 + 417 + input->filter.formatted.vlan_id = htons(ptype); 418 + if (mask.formatted.flow_type & TXGBE_ATR_L4TYPE_MASK) 419 + mask.formatted.vlan_id = htons(0xFFFF); 420 + else 421 + mask.formatted.vlan_id = htons(0xFFF8); 422 + 423 + /* determine if we need to drop or route the packet */ 424 + if (fsp->ring_cookie == RX_CLS_FLOW_DISC) 425 + input->action = TXGBE_RDB_FDIR_DROP_QUEUE; 426 + else 427 + input->action = fsp->ring_cookie; 428 + 429 + spin_lock(&txgbe->fdir_perfect_lock); 430 + 431 + if (hlist_empty(&txgbe->fdir_filter_list)) { 432 + /* save mask and program input mask into HW */ 433 + memcpy(&txgbe->fdir_mask, &mask, sizeof(mask)); 434 + err = txgbe_fdir_set_input_mask(wx, &mask); 435 + if (err) 436 + goto err_unlock; 437 + } else if (memcmp(&txgbe->fdir_mask, &mask, sizeof(mask))) { 438 + wx_err(wx, "Hardware only supports one mask per port. To change the mask you must first delete all the rules.\n"); 439 + goto err_unlock; 440 + } 441 + 442 + /* apply mask and compute/store hash */ 443 + txgbe_atr_compute_perfect_hash(&input->filter, &mask); 444 + 445 + /* check if new entry does not exist on filter list */ 446 + if (txgbe_match_ethtool_fdir_entry(txgbe, input)) 447 + goto err_unlock; 448 + 449 + /* only program filters to hardware if the net device is running, as 450 + * we store the filters in the Rx buffer which is not allocated when 451 + * the device is down 452 + */ 453 + if (netif_running(wx->netdev)) { 454 + err = txgbe_fdir_write_perfect_filter(wx, &input->filter, 455 + input->sw_idx, queue); 456 + if (err) 457 + goto err_unlock; 458 + } 459 + 460 + txgbe_update_ethtool_fdir_entry(txgbe, input, input->sw_idx); 461 + 462 + spin_unlock(&txgbe->fdir_perfect_lock); 463 + 464 + return 0; 465 + err_unlock: 466 + spin_unlock(&txgbe->fdir_perfect_lock); 467 + err_out: 468 + kfree(input); 469 + return err; 470 + } 471 + 472 + static int txgbe_del_ethtool_fdir_entry(struct txgbe *txgbe, 473 + struct ethtool_rxnfc *cmd) 474 + { 475 + struct ethtool_rx_flow_spec *fsp = 476 + (struct ethtool_rx_flow_spec *)&cmd->fs; 477 + int err = 0; 478 + 479 + spin_lock(&txgbe->fdir_perfect_lock); 480 + err = txgbe_update_ethtool_fdir_entry(txgbe, NULL, fsp->location); 481 + spin_unlock(&txgbe->fdir_perfect_lock); 482 + 483 + return err; 484 + } 485 + 486 + static int txgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 487 + { 488 + struct wx *wx = netdev_priv(dev); 489 + struct txgbe *txgbe = wx->priv; 490 + int ret = -EOPNOTSUPP; 491 + 492 + switch (cmd->cmd) { 493 + case ETHTOOL_SRXCLSRLINS: 494 + ret = txgbe_add_ethtool_fdir_entry(txgbe, cmd); 495 + break; 496 + case ETHTOOL_SRXCLSRLDEL: 497 + ret = txgbe_del_ethtool_fdir_entry(txgbe, cmd); 498 + break; 499 + default: 500 + break; 501 + } 502 + 503 + return ret; 504 + } 505 + 83 506 static const struct ethtool_ops txgbe_ethtool_ops = { 84 507 .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 85 508 ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ, ··· 525 100 .set_coalesce = wx_set_coalesce, 526 101 .get_channels = wx_get_channels, 527 102 .set_channels = txgbe_set_channels, 103 + .get_rxnfc = txgbe_get_rxnfc, 104 + .set_rxnfc = txgbe_set_rxnfc, 528 105 .get_msglevel = wx_get_msglevel, 529 106 .set_msglevel = wx_set_msglevel, 530 107 };
+643
drivers/net/ethernet/wangxun/txgbe/txgbe_fdir.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ 3 + 4 + #include <linux/string.h> 5 + #include <linux/types.h> 6 + #include <linux/pci.h> 7 + 8 + #include "../libwx/wx_type.h" 9 + #include "../libwx/wx_lib.h" 10 + #include "../libwx/wx_hw.h" 11 + #include "txgbe_type.h" 12 + #include "txgbe_fdir.h" 13 + 14 + /* These defines allow us to quickly generate all of the necessary instructions 15 + * in the function below by simply calling out TXGBE_COMPUTE_SIG_HASH_ITERATION 16 + * for values 0 through 15 17 + */ 18 + #define TXGBE_ATR_COMMON_HASH_KEY \ 19 + (TXGBE_ATR_BUCKET_HASH_KEY & TXGBE_ATR_SIGNATURE_HASH_KEY) 20 + #define TXGBE_COMPUTE_SIG_HASH_ITERATION(_n) \ 21 + do { \ 22 + u32 n = (_n); \ 23 + if (TXGBE_ATR_COMMON_HASH_KEY & (0x01 << n)) \ 24 + common_hash ^= lo_hash_dword >> n; \ 25 + else if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << n)) \ 26 + bucket_hash ^= lo_hash_dword >> n; \ 27 + else if (TXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << n)) \ 28 + sig_hash ^= lo_hash_dword << (16 - n); \ 29 + if (TXGBE_ATR_COMMON_HASH_KEY & (0x01 << (n + 16))) \ 30 + common_hash ^= hi_hash_dword >> n; \ 31 + else if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << (n + 16))) \ 32 + bucket_hash ^= hi_hash_dword >> n; \ 33 + else if (TXGBE_ATR_SIGNATURE_HASH_KEY & (0x01 << (n + 16))) \ 34 + sig_hash ^= hi_hash_dword << (16 - n); \ 35 + } while (0) 36 + 37 + /** 38 + * txgbe_atr_compute_sig_hash - Compute the signature hash 39 + * @input: input bitstream to compute the hash on 40 + * @common: compressed common input dword 41 + * @hash: pointer to the computed hash 42 + * 43 + * This function is almost identical to the function above but contains 44 + * several optimizations such as unwinding all of the loops, letting the 45 + * compiler work out all of the conditional ifs since the keys are static 46 + * defines, and computing two keys at once since the hashed dword stream 47 + * will be the same for both keys. 48 + **/ 49 + static void txgbe_atr_compute_sig_hash(union txgbe_atr_hash_dword input, 50 + union txgbe_atr_hash_dword common, 51 + u32 *hash) 52 + { 53 + u32 sig_hash = 0, bucket_hash = 0, common_hash = 0; 54 + u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan; 55 + u32 i; 56 + 57 + /* record the flow_vm_vlan bits as they are a key part to the hash */ 58 + flow_vm_vlan = ntohl(input.dword); 59 + 60 + /* generate common hash dword */ 61 + hi_hash_dword = ntohl(common.dword); 62 + 63 + /* low dword is word swapped version of common */ 64 + lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16); 65 + 66 + /* apply flow ID/VM pool/VLAN ID bits to hash words */ 67 + hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16); 68 + 69 + /* Process bits 0 and 16 */ 70 + TXGBE_COMPUTE_SIG_HASH_ITERATION(0); 71 + 72 + /* apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to 73 + * delay this because bit 0 of the stream should not be processed 74 + * so we do not add the VLAN until after bit 0 was processed 75 + */ 76 + lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16); 77 + 78 + /* Process remaining 30 bit of the key */ 79 + for (i = 1; i <= 15; i++) 80 + TXGBE_COMPUTE_SIG_HASH_ITERATION(i); 81 + 82 + /* combine common_hash result with signature and bucket hashes */ 83 + bucket_hash ^= common_hash; 84 + bucket_hash &= TXGBE_ATR_HASH_MASK; 85 + 86 + sig_hash ^= common_hash << 16; 87 + sig_hash &= TXGBE_ATR_HASH_MASK << 16; 88 + 89 + /* return completed signature hash */ 90 + *hash = sig_hash ^ bucket_hash; 91 + } 92 + 93 + #define TXGBE_COMPUTE_BKT_HASH_ITERATION(_n) \ 94 + do { \ 95 + u32 n = (_n); \ 96 + if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << n)) \ 97 + bucket_hash ^= lo_hash_dword >> n; \ 98 + if (TXGBE_ATR_BUCKET_HASH_KEY & (0x01 << (n + 16))) \ 99 + bucket_hash ^= hi_hash_dword >> n; \ 100 + } while (0) 101 + 102 + /** 103 + * txgbe_atr_compute_perfect_hash - Compute the perfect filter hash 104 + * @input: input bitstream to compute the hash on 105 + * @input_mask: mask for the input bitstream 106 + * 107 + * This function serves two main purposes. First it applies the input_mask 108 + * to the atr_input resulting in a cleaned up atr_input data stream. 109 + * Secondly it computes the hash and stores it in the bkt_hash field at 110 + * the end of the input byte stream. This way it will be available for 111 + * future use without needing to recompute the hash. 112 + **/ 113 + void txgbe_atr_compute_perfect_hash(union txgbe_atr_input *input, 114 + union txgbe_atr_input *input_mask) 115 + { 116 + u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan; 117 + u32 bucket_hash = 0; 118 + __be32 hi_dword = 0; 119 + u32 i = 0; 120 + 121 + /* Apply masks to input data */ 122 + for (i = 0; i < 11; i++) 123 + input->dword_stream[i] &= input_mask->dword_stream[i]; 124 + 125 + /* record the flow_vm_vlan bits as they are a key part to the hash */ 126 + flow_vm_vlan = ntohl(input->dword_stream[0]); 127 + 128 + /* generate common hash dword */ 129 + for (i = 1; i <= 10; i++) 130 + hi_dword ^= input->dword_stream[i]; 131 + hi_hash_dword = ntohl(hi_dword); 132 + 133 + /* low dword is word swapped version of common */ 134 + lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16); 135 + 136 + /* apply flow ID/VM pool/VLAN ID bits to hash words */ 137 + hi_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan >> 16); 138 + 139 + /* Process bits 0 and 16 */ 140 + TXGBE_COMPUTE_BKT_HASH_ITERATION(0); 141 + 142 + /* apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to 143 + * delay this because bit 0 of the stream should not be processed 144 + * so we do not add the VLAN until after bit 0 was processed 145 + */ 146 + lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16); 147 + 148 + /* Process remaining 30 bit of the key */ 149 + for (i = 1; i <= 15; i++) 150 + TXGBE_COMPUTE_BKT_HASH_ITERATION(i); 151 + 152 + /* Limit hash to 13 bits since max bucket count is 8K. 153 + * Store result at the end of the input stream. 154 + */ 155 + input->formatted.bkt_hash = (__force __be16)(bucket_hash & 0x1FFF); 156 + } 157 + 158 + static int txgbe_fdir_check_cmd_complete(struct wx *wx) 159 + { 160 + u32 val; 161 + 162 + return read_poll_timeout_atomic(rd32, val, 163 + !(val & TXGBE_RDB_FDIR_CMD_CMD_MASK), 164 + 10, 100, false, 165 + wx, TXGBE_RDB_FDIR_CMD); 166 + } 167 + 168 + /** 169 + * txgbe_fdir_add_signature_filter - Adds a signature hash filter 170 + * @wx: pointer to hardware structure 171 + * @input: unique input dword 172 + * @common: compressed common input dword 173 + * @queue: queue index to direct traffic to 174 + * 175 + * @return: 0 on success and negative on failure 176 + **/ 177 + static int txgbe_fdir_add_signature_filter(struct wx *wx, 178 + union txgbe_atr_hash_dword input, 179 + union txgbe_atr_hash_dword common, 180 + u8 queue) 181 + { 182 + u32 fdirhashcmd, fdircmd; 183 + u8 flow_type; 184 + int err; 185 + 186 + /* Get the flow_type in order to program FDIRCMD properly 187 + * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 188 + * fifth is FDIRCMD.TUNNEL_FILTER 189 + */ 190 + flow_type = input.formatted.flow_type; 191 + switch (flow_type) { 192 + case TXGBE_ATR_FLOW_TYPE_TCPV4: 193 + case TXGBE_ATR_FLOW_TYPE_UDPV4: 194 + case TXGBE_ATR_FLOW_TYPE_SCTPV4: 195 + case TXGBE_ATR_FLOW_TYPE_TCPV6: 196 + case TXGBE_ATR_FLOW_TYPE_UDPV6: 197 + case TXGBE_ATR_FLOW_TYPE_SCTPV6: 198 + break; 199 + default: 200 + wx_err(wx, "Error on flow type input\n"); 201 + return -EINVAL; 202 + } 203 + 204 + /* configure FDIRCMD register */ 205 + fdircmd = TXGBE_RDB_FDIR_CMD_CMD_ADD_FLOW | 206 + TXGBE_RDB_FDIR_CMD_FILTER_UPDATE | 207 + TXGBE_RDB_FDIR_CMD_LAST | TXGBE_RDB_FDIR_CMD_QUEUE_EN; 208 + fdircmd |= TXGBE_RDB_FDIR_CMD_FLOW_TYPE(flow_type); 209 + fdircmd |= TXGBE_RDB_FDIR_CMD_RX_QUEUE(queue); 210 + 211 + txgbe_atr_compute_sig_hash(input, common, &fdirhashcmd); 212 + fdirhashcmd |= TXGBE_RDB_FDIR_HASH_BUCKET_VALID; 213 + wr32(wx, TXGBE_RDB_FDIR_HASH, fdirhashcmd); 214 + wr32(wx, TXGBE_RDB_FDIR_CMD, fdircmd); 215 + 216 + wx_dbg(wx, "Tx Queue=%x hash=%x\n", queue, (u32)fdirhashcmd); 217 + 218 + err = txgbe_fdir_check_cmd_complete(wx); 219 + if (err) 220 + wx_err(wx, "Flow Director command did not complete!\n"); 221 + 222 + return err; 223 + } 224 + 225 + void txgbe_atr(struct wx_ring *ring, struct wx_tx_buffer *first, u8 ptype) 226 + { 227 + union txgbe_atr_hash_dword common = { .dword = 0 }; 228 + union txgbe_atr_hash_dword input = { .dword = 0 }; 229 + struct wx_q_vector *q_vector = ring->q_vector; 230 + struct wx_dec_ptype dptype; 231 + union network_header { 232 + struct ipv6hdr *ipv6; 233 + struct iphdr *ipv4; 234 + void *raw; 235 + } hdr; 236 + struct tcphdr *th; 237 + 238 + /* if ring doesn't have a interrupt vector, cannot perform ATR */ 239 + if (!q_vector) 240 + return; 241 + 242 + ring->atr_count++; 243 + dptype = wx_decode_ptype(ptype); 244 + if (dptype.etype) { 245 + if (WX_PTYPE_TYPL4(ptype) != WX_PTYPE_TYP_TCP) 246 + return; 247 + hdr.raw = (void *)skb_inner_network_header(first->skb); 248 + th = inner_tcp_hdr(first->skb); 249 + } else { 250 + if (WX_PTYPE_PKT(ptype) != WX_PTYPE_PKT_IP || 251 + WX_PTYPE_TYPL4(ptype) != WX_PTYPE_TYP_TCP) 252 + return; 253 + hdr.raw = (void *)skb_network_header(first->skb); 254 + th = tcp_hdr(first->skb); 255 + } 256 + 257 + /* skip this packet since it is invalid or the socket is closing */ 258 + if (!th || th->fin) 259 + return; 260 + 261 + /* sample on all syn packets or once every atr sample count */ 262 + if (!th->syn && ring->atr_count < ring->atr_sample_rate) 263 + return; 264 + 265 + /* reset sample count */ 266 + ring->atr_count = 0; 267 + 268 + /* src and dst are inverted, think how the receiver sees them 269 + * 270 + * The input is broken into two sections, a non-compressed section 271 + * containing vm_pool, vlan_id, and flow_type. The rest of the data 272 + * is XORed together and stored in the compressed dword. 273 + */ 274 + input.formatted.vlan_id = htons((u16)ptype); 275 + 276 + /* since src port and flex bytes occupy the same word XOR them together 277 + * and write the value to source port portion of compressed dword 278 + */ 279 + if (first->tx_flags & WX_TX_FLAGS_SW_VLAN) 280 + common.port.src ^= th->dest ^ first->skb->protocol; 281 + else if (first->tx_flags & WX_TX_FLAGS_HW_VLAN) 282 + common.port.src ^= th->dest ^ first->skb->vlan_proto; 283 + else 284 + common.port.src ^= th->dest ^ first->protocol; 285 + common.port.dst ^= th->source; 286 + 287 + if (WX_PTYPE_PKT_IPV6 & WX_PTYPE_PKT(ptype)) { 288 + input.formatted.flow_type = TXGBE_ATR_FLOW_TYPE_TCPV6; 289 + common.ip ^= hdr.ipv6->saddr.s6_addr32[0] ^ 290 + hdr.ipv6->saddr.s6_addr32[1] ^ 291 + hdr.ipv6->saddr.s6_addr32[2] ^ 292 + hdr.ipv6->saddr.s6_addr32[3] ^ 293 + hdr.ipv6->daddr.s6_addr32[0] ^ 294 + hdr.ipv6->daddr.s6_addr32[1] ^ 295 + hdr.ipv6->daddr.s6_addr32[2] ^ 296 + hdr.ipv6->daddr.s6_addr32[3]; 297 + } else { 298 + input.formatted.flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4; 299 + common.ip ^= hdr.ipv4->saddr ^ hdr.ipv4->daddr; 300 + } 301 + 302 + /* This assumes the Rx queue and Tx queue are bound to the same CPU */ 303 + txgbe_fdir_add_signature_filter(q_vector->wx, input, common, 304 + ring->queue_index); 305 + } 306 + 307 + int txgbe_fdir_set_input_mask(struct wx *wx, union txgbe_atr_input *input_mask) 308 + { 309 + u32 fdirm = 0, fdirtcpm = 0, flex = 0; 310 + 311 + /* Program the relevant mask registers. If src/dst_port or src/dst_addr 312 + * are zero, then assume a full mask for that field. Also assume that 313 + * a VLAN of 0 is unspecified, so mask that out as well. L4type 314 + * cannot be masked out in this implementation. 315 + * 316 + * This also assumes IPv4 only. IPv6 masking isn't supported at this 317 + * point in time. 318 + */ 319 + 320 + /* verify bucket hash is cleared on hash generation */ 321 + if (input_mask->formatted.bkt_hash) 322 + wx_dbg(wx, "bucket hash should always be 0 in mask\n"); 323 + 324 + /* Program FDIRM and verify partial masks */ 325 + switch (input_mask->formatted.vm_pool & 0x7F) { 326 + case 0x0: 327 + fdirm |= TXGBE_RDB_FDIR_OTHER_MSK_POOL; 328 + break; 329 + case 0x7F: 330 + break; 331 + default: 332 + wx_err(wx, "Error on vm pool mask\n"); 333 + return -EINVAL; 334 + } 335 + 336 + switch (input_mask->formatted.flow_type & TXGBE_ATR_L4TYPE_MASK) { 337 + case 0x0: 338 + fdirm |= TXGBE_RDB_FDIR_OTHER_MSK_L4P; 339 + if (input_mask->formatted.dst_port || 340 + input_mask->formatted.src_port) { 341 + wx_err(wx, "Error on src/dst port mask\n"); 342 + return -EINVAL; 343 + } 344 + break; 345 + case TXGBE_ATR_L4TYPE_MASK: 346 + break; 347 + default: 348 + wx_err(wx, "Error on flow type mask\n"); 349 + return -EINVAL; 350 + } 351 + 352 + /* Now mask VM pool and destination IPv6 - bits 5 and 2 */ 353 + wr32(wx, TXGBE_RDB_FDIR_OTHER_MSK, fdirm); 354 + 355 + flex = rd32(wx, TXGBE_RDB_FDIR_FLEX_CFG(0)); 356 + flex &= ~TXGBE_RDB_FDIR_FLEX_CFG_FIELD0; 357 + flex |= (TXGBE_RDB_FDIR_FLEX_CFG_BASE_MAC | 358 + TXGBE_RDB_FDIR_FLEX_CFG_OFST(0x6)); 359 + 360 + switch ((__force u16)input_mask->formatted.flex_bytes & 0xFFFF) { 361 + case 0x0000: 362 + /* Mask Flex Bytes */ 363 + flex |= TXGBE_RDB_FDIR_FLEX_CFG_MSK; 364 + break; 365 + case 0xFFFF: 366 + break; 367 + default: 368 + wx_err(wx, "Error on flexible byte mask\n"); 369 + return -EINVAL; 370 + } 371 + wr32(wx, TXGBE_RDB_FDIR_FLEX_CFG(0), flex); 372 + 373 + /* store the TCP/UDP port masks, bit reversed from port layout */ 374 + fdirtcpm = ntohs(input_mask->formatted.dst_port); 375 + fdirtcpm <<= TXGBE_RDB_FDIR_PORT_DESTINATION_SHIFT; 376 + fdirtcpm |= ntohs(input_mask->formatted.src_port); 377 + 378 + /* write both the same so that UDP and TCP use the same mask */ 379 + wr32(wx, TXGBE_RDB_FDIR_TCP_MSK, ~fdirtcpm); 380 + wr32(wx, TXGBE_RDB_FDIR_UDP_MSK, ~fdirtcpm); 381 + wr32(wx, TXGBE_RDB_FDIR_SCTP_MSK, ~fdirtcpm); 382 + 383 + /* store source and destination IP masks (little-enian) */ 384 + wr32(wx, TXGBE_RDB_FDIR_SA4_MSK, 385 + ntohl(~input_mask->formatted.src_ip[0])); 386 + wr32(wx, TXGBE_RDB_FDIR_DA4_MSK, 387 + ntohl(~input_mask->formatted.dst_ip[0])); 388 + 389 + return 0; 390 + } 391 + 392 + int txgbe_fdir_write_perfect_filter(struct wx *wx, 393 + union txgbe_atr_input *input, 394 + u16 soft_id, u8 queue) 395 + { 396 + u32 fdirport, fdirvlan, fdirhash, fdircmd; 397 + int err = 0; 398 + 399 + /* currently IPv6 is not supported, must be programmed with 0 */ 400 + wr32(wx, TXGBE_RDB_FDIR_IP6(2), ntohl(input->formatted.src_ip[0])); 401 + wr32(wx, TXGBE_RDB_FDIR_IP6(1), ntohl(input->formatted.src_ip[1])); 402 + wr32(wx, TXGBE_RDB_FDIR_IP6(0), ntohl(input->formatted.src_ip[2])); 403 + 404 + /* record the source address (little-endian) */ 405 + wr32(wx, TXGBE_RDB_FDIR_SA, ntohl(input->formatted.src_ip[0])); 406 + 407 + /* record the first 32 bits of the destination address 408 + * (little-endian) 409 + */ 410 + wr32(wx, TXGBE_RDB_FDIR_DA, ntohl(input->formatted.dst_ip[0])); 411 + 412 + /* record source and destination port (little-endian)*/ 413 + fdirport = ntohs(input->formatted.dst_port); 414 + fdirport <<= TXGBE_RDB_FDIR_PORT_DESTINATION_SHIFT; 415 + fdirport |= ntohs(input->formatted.src_port); 416 + wr32(wx, TXGBE_RDB_FDIR_PORT, fdirport); 417 + 418 + /* record packet type and flex_bytes (little-endian) */ 419 + fdirvlan = ntohs(input->formatted.flex_bytes); 420 + fdirvlan <<= TXGBE_RDB_FDIR_FLEX_FLEX_SHIFT; 421 + fdirvlan |= ntohs(input->formatted.vlan_id); 422 + wr32(wx, TXGBE_RDB_FDIR_FLEX, fdirvlan); 423 + 424 + /* configure FDIRHASH register */ 425 + fdirhash = (__force u32)input->formatted.bkt_hash | 426 + TXGBE_RDB_FDIR_HASH_BUCKET_VALID | 427 + TXGBE_RDB_FDIR_HASH_SIG_SW_INDEX(soft_id); 428 + wr32(wx, TXGBE_RDB_FDIR_HASH, fdirhash); 429 + 430 + /* flush all previous writes to make certain registers are 431 + * programmed prior to issuing the command 432 + */ 433 + WX_WRITE_FLUSH(wx); 434 + 435 + /* configure FDIRCMD register */ 436 + fdircmd = TXGBE_RDB_FDIR_CMD_CMD_ADD_FLOW | 437 + TXGBE_RDB_FDIR_CMD_FILTER_UPDATE | 438 + TXGBE_RDB_FDIR_CMD_LAST | TXGBE_RDB_FDIR_CMD_QUEUE_EN; 439 + if (queue == TXGBE_RDB_FDIR_DROP_QUEUE) 440 + fdircmd |= TXGBE_RDB_FDIR_CMD_DROP; 441 + fdircmd |= TXGBE_RDB_FDIR_CMD_FLOW_TYPE(input->formatted.flow_type); 442 + fdircmd |= TXGBE_RDB_FDIR_CMD_RX_QUEUE(queue); 443 + fdircmd |= TXGBE_RDB_FDIR_CMD_VT_POOL(input->formatted.vm_pool); 444 + 445 + wr32(wx, TXGBE_RDB_FDIR_CMD, fdircmd); 446 + err = txgbe_fdir_check_cmd_complete(wx); 447 + if (err) 448 + wx_err(wx, "Flow Director command did not complete!\n"); 449 + 450 + return err; 451 + } 452 + 453 + int txgbe_fdir_erase_perfect_filter(struct wx *wx, 454 + union txgbe_atr_input *input, 455 + u16 soft_id) 456 + { 457 + u32 fdirhash, fdircmd; 458 + int err = 0; 459 + 460 + /* configure FDIRHASH register */ 461 + fdirhash = (__force u32)input->formatted.bkt_hash; 462 + fdirhash |= TXGBE_RDB_FDIR_HASH_SIG_SW_INDEX(soft_id); 463 + wr32(wx, TXGBE_RDB_FDIR_HASH, fdirhash); 464 + 465 + /* flush hash to HW */ 466 + WX_WRITE_FLUSH(wx); 467 + 468 + /* Query if filter is present */ 469 + wr32(wx, TXGBE_RDB_FDIR_CMD, TXGBE_RDB_FDIR_CMD_CMD_QUERY_REM_FILT); 470 + 471 + err = txgbe_fdir_check_cmd_complete(wx); 472 + if (err) { 473 + wx_err(wx, "Flow Director command did not complete!\n"); 474 + return err; 475 + } 476 + 477 + fdircmd = rd32(wx, TXGBE_RDB_FDIR_CMD); 478 + /* if filter exists in hardware then remove it */ 479 + if (fdircmd & TXGBE_RDB_FDIR_CMD_FILTER_VALID) { 480 + wr32(wx, TXGBE_RDB_FDIR_HASH, fdirhash); 481 + WX_WRITE_FLUSH(wx); 482 + wr32(wx, TXGBE_RDB_FDIR_CMD, 483 + TXGBE_RDB_FDIR_CMD_CMD_REMOVE_FLOW); 484 + } 485 + 486 + return 0; 487 + } 488 + 489 + /** 490 + * txgbe_fdir_enable - Initialize Flow Director control registers 491 + * @wx: pointer to hardware structure 492 + * @fdirctrl: value to write to flow director control register 493 + **/ 494 + static void txgbe_fdir_enable(struct wx *wx, u32 fdirctrl) 495 + { 496 + u32 val; 497 + int ret; 498 + 499 + /* Prime the keys for hashing */ 500 + wr32(wx, TXGBE_RDB_FDIR_HKEY, TXGBE_ATR_BUCKET_HASH_KEY); 501 + wr32(wx, TXGBE_RDB_FDIR_SKEY, TXGBE_ATR_SIGNATURE_HASH_KEY); 502 + 503 + wr32(wx, TXGBE_RDB_FDIR_CTL, fdirctrl); 504 + WX_WRITE_FLUSH(wx); 505 + ret = read_poll_timeout(rd32, val, val & TXGBE_RDB_FDIR_CTL_INIT_DONE, 506 + 1000, 10000, false, wx, TXGBE_RDB_FDIR_CTL); 507 + 508 + if (ret < 0) 509 + wx_dbg(wx, "Flow Director poll time exceeded!\n"); 510 + } 511 + 512 + /** 513 + * txgbe_init_fdir_signature -Initialize Flow Director sig filters 514 + * @wx: pointer to hardware structure 515 + **/ 516 + static void txgbe_init_fdir_signature(struct wx *wx) 517 + { 518 + u32 fdirctrl = TXGBE_FDIR_PBALLOC_64K; 519 + u32 flex = 0; 520 + 521 + flex = rd32(wx, TXGBE_RDB_FDIR_FLEX_CFG(0)); 522 + flex &= ~TXGBE_RDB_FDIR_FLEX_CFG_FIELD0; 523 + 524 + flex |= (TXGBE_RDB_FDIR_FLEX_CFG_BASE_MAC | 525 + TXGBE_RDB_FDIR_FLEX_CFG_OFST(0x6)); 526 + wr32(wx, TXGBE_RDB_FDIR_FLEX_CFG(0), flex); 527 + 528 + /* Continue setup of fdirctrl register bits: 529 + * Move the flexible bytes to use the ethertype - shift 6 words 530 + * Set the maximum length per hash bucket to 0xA filters 531 + * Send interrupt when 64 filters are left 532 + */ 533 + fdirctrl |= TXGBE_RDB_FDIR_CTL_HASH_BITS(0xF) | 534 + TXGBE_RDB_FDIR_CTL_MAX_LENGTH(0xA) | 535 + TXGBE_RDB_FDIR_CTL_FULL_THRESH(4); 536 + 537 + /* write hashes and fdirctrl register, poll for completion */ 538 + txgbe_fdir_enable(wx, fdirctrl); 539 + } 540 + 541 + /** 542 + * txgbe_init_fdir_perfect - Initialize Flow Director perfect filters 543 + * @wx: pointer to hardware structure 544 + **/ 545 + static void txgbe_init_fdir_perfect(struct wx *wx) 546 + { 547 + u32 fdirctrl = TXGBE_FDIR_PBALLOC_64K; 548 + 549 + /* Continue setup of fdirctrl register bits: 550 + * Turn perfect match filtering on 551 + * Report hash in RSS field of Rx wb descriptor 552 + * Initialize the drop queue 553 + * Move the flexible bytes to use the ethertype - shift 6 words 554 + * Set the maximum length per hash bucket to 0xA filters 555 + * Send interrupt when 64 (0x4 * 16) filters are left 556 + */ 557 + fdirctrl |= TXGBE_RDB_FDIR_CTL_PERFECT_MATCH | 558 + TXGBE_RDB_FDIR_CTL_DROP_Q(TXGBE_RDB_FDIR_DROP_QUEUE) | 559 + TXGBE_RDB_FDIR_CTL_HASH_BITS(0xF) | 560 + TXGBE_RDB_FDIR_CTL_MAX_LENGTH(0xA) | 561 + TXGBE_RDB_FDIR_CTL_FULL_THRESH(4); 562 + 563 + /* write hashes and fdirctrl register, poll for completion */ 564 + txgbe_fdir_enable(wx, fdirctrl); 565 + } 566 + 567 + static void txgbe_fdir_filter_restore(struct wx *wx) 568 + { 569 + struct txgbe_fdir_filter *filter; 570 + struct txgbe *txgbe = wx->priv; 571 + struct hlist_node *node; 572 + u8 queue = 0; 573 + int ret = 0; 574 + 575 + spin_lock(&txgbe->fdir_perfect_lock); 576 + 577 + if (!hlist_empty(&txgbe->fdir_filter_list)) 578 + ret = txgbe_fdir_set_input_mask(wx, &txgbe->fdir_mask); 579 + 580 + if (ret) 581 + goto unlock; 582 + 583 + hlist_for_each_entry_safe(filter, node, 584 + &txgbe->fdir_filter_list, fdir_node) { 585 + if (filter->action == TXGBE_RDB_FDIR_DROP_QUEUE) { 586 + queue = TXGBE_RDB_FDIR_DROP_QUEUE; 587 + } else { 588 + u32 ring = ethtool_get_flow_spec_ring(filter->action); 589 + 590 + if (ring >= wx->num_rx_queues) { 591 + wx_err(wx, "FDIR restore failed, ring:%u\n", 592 + ring); 593 + continue; 594 + } 595 + 596 + /* Map the ring onto the absolute queue index */ 597 + queue = wx->rx_ring[ring]->reg_idx; 598 + } 599 + 600 + ret = txgbe_fdir_write_perfect_filter(wx, 601 + &filter->filter, 602 + filter->sw_idx, 603 + queue); 604 + if (ret) 605 + wx_err(wx, "FDIR restore failed, index:%u\n", 606 + filter->sw_idx); 607 + } 608 + 609 + unlock: 610 + spin_unlock(&txgbe->fdir_perfect_lock); 611 + } 612 + 613 + void txgbe_configure_fdir(struct wx *wx) 614 + { 615 + wx_disable_sec_rx_path(wx); 616 + 617 + if (test_bit(WX_FLAG_FDIR_HASH, wx->flags)) { 618 + txgbe_init_fdir_signature(wx); 619 + } else if (test_bit(WX_FLAG_FDIR_PERFECT, wx->flags)) { 620 + txgbe_init_fdir_perfect(wx); 621 + txgbe_fdir_filter_restore(wx); 622 + } 623 + 624 + wx_enable_sec_rx_path(wx); 625 + } 626 + 627 + void txgbe_fdir_filter_exit(struct wx *wx) 628 + { 629 + struct txgbe_fdir_filter *filter; 630 + struct txgbe *txgbe = wx->priv; 631 + struct hlist_node *node; 632 + 633 + spin_lock(&txgbe->fdir_perfect_lock); 634 + 635 + hlist_for_each_entry_safe(filter, node, 636 + &txgbe->fdir_filter_list, fdir_node) { 637 + hlist_del(&filter->fdir_node); 638 + kfree(filter); 639 + } 640 + txgbe->fdir_filter_count = 0; 641 + 642 + spin_unlock(&txgbe->fdir_perfect_lock); 643 + }
+20
drivers/net/ethernet/wangxun/txgbe/txgbe_fdir.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ 3 + 4 + #ifndef _TXGBE_FDIR_H_ 5 + #define _TXGBE_FDIR_H_ 6 + 7 + void txgbe_atr_compute_perfect_hash(union txgbe_atr_input *input, 8 + union txgbe_atr_input *input_mask); 9 + void txgbe_atr(struct wx_ring *ring, struct wx_tx_buffer *first, u8 ptype); 10 + int txgbe_fdir_set_input_mask(struct wx *wx, union txgbe_atr_input *input_mask); 11 + int txgbe_fdir_write_perfect_filter(struct wx *wx, 12 + union txgbe_atr_input *input, 13 + u16 soft_id, u8 queue); 14 + int txgbe_fdir_erase_perfect_filter(struct wx *wx, 15 + union txgbe_atr_input *input, 16 + u16 soft_id); 17 + void txgbe_configure_fdir(struct wx *wx); 18 + void txgbe_fdir_filter_exit(struct wx *wx); 19 + 20 + #endif /* _TXGBE_FDIR_H_ */
+18
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
··· 18 18 #include "txgbe_hw.h" 19 19 #include "txgbe_phy.h" 20 20 #include "txgbe_irq.h" 21 + #include "txgbe_fdir.h" 21 22 #include "txgbe_ethtool.h" 22 23 23 24 char txgbe_driver_name[] = "txgbe"; ··· 258 257 num_online_cpus()); 259 258 wx->rss_enabled = true; 260 259 260 + wx->ring_feature[RING_F_FDIR].limit = min_t(int, TXGBE_MAX_FDIR_INDICES, 261 + num_online_cpus()); 262 + set_bit(WX_FLAG_FDIR_CAPABLE, wx->flags); 263 + set_bit(WX_FLAG_FDIR_HASH, wx->flags); 264 + wx->atr_sample_rate = TXGBE_DEFAULT_ATR_SAMPLE_RATE; 265 + wx->atr = txgbe_atr; 266 + wx->configure_fdir = txgbe_configure_fdir; 267 + 261 268 /* enable itr by default in dynamic mode */ 262 269 wx->rx_itr_setting = 1; 263 270 wx->tx_itr_setting = 1; ··· 281 272 wx->do_reset = txgbe_do_reset; 282 273 283 274 return 0; 275 + } 276 + 277 + static void txgbe_init_fdir(struct txgbe *txgbe) 278 + { 279 + txgbe->fdir_filter_count = 0; 280 + spin_lock_init(&txgbe->fdir_perfect_lock); 284 281 } 285 282 286 283 /** ··· 367 352 txgbe_down(wx); 368 353 wx_free_irq(wx); 369 354 wx_free_resources(wx); 355 + txgbe_fdir_filter_exit(wx); 370 356 wx_control_hw(wx, false); 371 357 372 358 return 0; ··· 675 659 676 660 txgbe->wx = wx; 677 661 wx->priv = txgbe; 662 + 663 + txgbe_init_fdir(txgbe); 678 664 679 665 err = txgbe_setup_misc_irq(txgbe); 680 666 if (err)
+147
drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
··· 89 89 #define TXGBE_XPCS_IDA_ADDR 0x13000 90 90 #define TXGBE_XPCS_IDA_DATA 0x13004 91 91 92 + /********************************* Flow Director *****************************/ 93 + #define TXGBE_RDB_FDIR_DROP_QUEUE 127 94 + #define TXGBE_RDB_FDIR_CTL 0x19500 95 + #define TXGBE_RDB_FDIR_CTL_INIT_DONE BIT(3) 96 + #define TXGBE_RDB_FDIR_CTL_PERFECT_MATCH BIT(4) 97 + #define TXGBE_RDB_FDIR_CTL_DROP_Q(v) FIELD_PREP(GENMASK(14, 8), v) 98 + #define TXGBE_RDB_FDIR_CTL_HASH_BITS(v) FIELD_PREP(GENMASK(23, 20), v) 99 + #define TXGBE_RDB_FDIR_CTL_MAX_LENGTH(v) FIELD_PREP(GENMASK(27, 24), v) 100 + #define TXGBE_RDB_FDIR_CTL_FULL_THRESH(v) FIELD_PREP(GENMASK(31, 28), v) 101 + #define TXGBE_RDB_FDIR_IP6(_i) (0x1950C + ((_i) * 4)) /* 0-2 */ 102 + #define TXGBE_RDB_FDIR_SA 0x19518 103 + #define TXGBE_RDB_FDIR_DA 0x1951C 104 + #define TXGBE_RDB_FDIR_PORT 0x19520 105 + #define TXGBE_RDB_FDIR_PORT_DESTINATION_SHIFT 16 106 + #define TXGBE_RDB_FDIR_FLEX 0x19524 107 + #define TXGBE_RDB_FDIR_FLEX_FLEX_SHIFT 16 108 + #define TXGBE_RDB_FDIR_HASH 0x19528 109 + #define TXGBE_RDB_FDIR_HASH_SIG_SW_INDEX(v) FIELD_PREP(GENMASK(31, 16), v) 110 + #define TXGBE_RDB_FDIR_HASH_BUCKET_VALID BIT(15) 111 + #define TXGBE_RDB_FDIR_CMD 0x1952C 112 + #define TXGBE_RDB_FDIR_CMD_CMD_MASK GENMASK(1, 0) 113 + #define TXGBE_RDB_FDIR_CMD_CMD(v) FIELD_PREP(GENMASK(1, 0), v) 114 + #define TXGBE_RDB_FDIR_CMD_CMD_ADD_FLOW TXGBE_RDB_FDIR_CMD_CMD(1) 115 + #define TXGBE_RDB_FDIR_CMD_CMD_REMOVE_FLOW TXGBE_RDB_FDIR_CMD_CMD(2) 116 + #define TXGBE_RDB_FDIR_CMD_CMD_QUERY_REM_FILT TXGBE_RDB_FDIR_CMD_CMD(3) 117 + #define TXGBE_RDB_FDIR_CMD_FILTER_VALID BIT(2) 118 + #define TXGBE_RDB_FDIR_CMD_FILTER_UPDATE BIT(3) 119 + #define TXGBE_RDB_FDIR_CMD_FLOW_TYPE(v) FIELD_PREP(GENMASK(6, 5), v) 120 + #define TXGBE_RDB_FDIR_CMD_DROP BIT(9) 121 + #define TXGBE_RDB_FDIR_CMD_LAST BIT(11) 122 + #define TXGBE_RDB_FDIR_CMD_QUEUE_EN BIT(15) 123 + #define TXGBE_RDB_FDIR_CMD_RX_QUEUE(v) FIELD_PREP(GENMASK(22, 16), v) 124 + #define TXGBE_RDB_FDIR_CMD_VT_POOL(v) FIELD_PREP(GENMASK(29, 24), v) 125 + #define TXGBE_RDB_FDIR_DA4_MSK 0x1953C 126 + #define TXGBE_RDB_FDIR_SA4_MSK 0x19540 127 + #define TXGBE_RDB_FDIR_TCP_MSK 0x19544 128 + #define TXGBE_RDB_FDIR_UDP_MSK 0x19548 129 + #define TXGBE_RDB_FDIR_SCTP_MSK 0x19560 130 + #define TXGBE_RDB_FDIR_HKEY 0x19568 131 + #define TXGBE_RDB_FDIR_SKEY 0x1956C 132 + #define TXGBE_RDB_FDIR_OTHER_MSK 0x19570 133 + #define TXGBE_RDB_FDIR_OTHER_MSK_POOL BIT(2) 134 + #define TXGBE_RDB_FDIR_OTHER_MSK_L4P BIT(3) 135 + #define TXGBE_RDB_FDIR_FLEX_CFG(_i) (0x19580 + ((_i) * 4)) 136 + #define TXGBE_RDB_FDIR_FLEX_CFG_FIELD0 GENMASK(7, 0) 137 + #define TXGBE_RDB_FDIR_FLEX_CFG_BASE_MAC FIELD_PREP(GENMASK(1, 0), 0) 138 + #define TXGBE_RDB_FDIR_FLEX_CFG_MSK BIT(2) 139 + #define TXGBE_RDB_FDIR_FLEX_CFG_OFST(v) FIELD_PREP(GENMASK(7, 3), v) 140 + 92 141 /* Checksum and EEPROM pointers */ 93 142 #define TXGBE_EEPROM_LAST_WORD 0x800 94 143 #define TXGBE_EEPROM_CHECKSUM 0x2F ··· 160 111 #define TXGBE_SP_VFT_TBL_SIZE 128 161 112 #define TXGBE_SP_RX_PB_SIZE 512 162 113 #define TXGBE_SP_TDB_PB_SZ (160 * 1024) /* 160KB Packet Buffer */ 114 + 115 + #define TXGBE_DEFAULT_ATR_SAMPLE_RATE 20 116 + 117 + /* Software ATR hash keys */ 118 + #define TXGBE_ATR_BUCKET_HASH_KEY 0x3DAD14E2 119 + #define TXGBE_ATR_SIGNATURE_HASH_KEY 0x174D3614 120 + 121 + /* Software ATR input stream values and masks */ 122 + #define TXGBE_ATR_HASH_MASK 0x7fff 123 + #define TXGBE_ATR_L4TYPE_MASK 0x3 124 + #define TXGBE_ATR_L4TYPE_UDP 0x1 125 + #define TXGBE_ATR_L4TYPE_TCP 0x2 126 + #define TXGBE_ATR_L4TYPE_SCTP 0x3 127 + #define TXGBE_ATR_L4TYPE_IPV6_MASK 0x4 128 + #define TXGBE_ATR_L4TYPE_TUNNEL_MASK 0x10 129 + 130 + enum txgbe_atr_flow_type { 131 + TXGBE_ATR_FLOW_TYPE_IPV4 = 0x0, 132 + TXGBE_ATR_FLOW_TYPE_UDPV4 = 0x1, 133 + TXGBE_ATR_FLOW_TYPE_TCPV4 = 0x2, 134 + TXGBE_ATR_FLOW_TYPE_SCTPV4 = 0x3, 135 + TXGBE_ATR_FLOW_TYPE_IPV6 = 0x4, 136 + TXGBE_ATR_FLOW_TYPE_UDPV6 = 0x5, 137 + TXGBE_ATR_FLOW_TYPE_TCPV6 = 0x6, 138 + TXGBE_ATR_FLOW_TYPE_SCTPV6 = 0x7, 139 + TXGBE_ATR_FLOW_TYPE_TUNNELED_IPV4 = 0x10, 140 + TXGBE_ATR_FLOW_TYPE_TUNNELED_UDPV4 = 0x11, 141 + TXGBE_ATR_FLOW_TYPE_TUNNELED_TCPV4 = 0x12, 142 + TXGBE_ATR_FLOW_TYPE_TUNNELED_SCTPV4 = 0x13, 143 + TXGBE_ATR_FLOW_TYPE_TUNNELED_IPV6 = 0x14, 144 + TXGBE_ATR_FLOW_TYPE_TUNNELED_UDPV6 = 0x15, 145 + TXGBE_ATR_FLOW_TYPE_TUNNELED_TCPV6 = 0x16, 146 + TXGBE_ATR_FLOW_TYPE_TUNNELED_SCTPV6 = 0x17, 147 + }; 148 + 149 + /* Flow Director ATR input struct. */ 150 + union txgbe_atr_input { 151 + /* Byte layout in order, all values with MSB first: 152 + * 153 + * vm_pool - 1 byte 154 + * flow_type - 1 byte 155 + * vlan_id - 2 bytes 156 + * dst_ip - 16 bytes 157 + * src_ip - 16 bytes 158 + * src_port - 2 bytes 159 + * dst_port - 2 bytes 160 + * flex_bytes - 2 bytes 161 + * bkt_hash - 2 bytes 162 + */ 163 + struct { 164 + u8 vm_pool; 165 + u8 flow_type; 166 + __be16 vlan_id; 167 + __be32 dst_ip[4]; 168 + __be32 src_ip[4]; 169 + __be16 src_port; 170 + __be16 dst_port; 171 + __be16 flex_bytes; 172 + __be16 bkt_hash; 173 + } formatted; 174 + __be32 dword_stream[11]; 175 + }; 176 + 177 + /* Flow Director compressed ATR hash input struct */ 178 + union txgbe_atr_hash_dword { 179 + struct { 180 + u8 vm_pool; 181 + u8 flow_type; 182 + __be16 vlan_id; 183 + } formatted; 184 + __be32 ip; 185 + struct { 186 + __be16 src; 187 + __be16 dst; 188 + } port; 189 + __be16 flex_bytes; 190 + __be32 dword; 191 + }; 192 + 193 + enum txgbe_fdir_pballoc_type { 194 + TXGBE_FDIR_PBALLOC_NONE = 0, 195 + TXGBE_FDIR_PBALLOC_64K = 1, 196 + TXGBE_FDIR_PBALLOC_128K = 2, 197 + TXGBE_FDIR_PBALLOC_256K = 3, 198 + }; 199 + 200 + struct txgbe_fdir_filter { 201 + struct hlist_node fdir_node; 202 + union txgbe_atr_input filter; 203 + u16 sw_idx; 204 + u16 action; 205 + }; 163 206 164 207 /* TX/RX descriptor defines */ 165 208 #define TXGBE_DEFAULT_TXD 512 ··· 337 196 struct gpio_chip *gpio; 338 197 unsigned int gpio_irq; 339 198 unsigned int link_irq; 199 + 200 + /* flow director */ 201 + struct hlist_head fdir_filter_list; 202 + union txgbe_atr_input fdir_mask; 203 + int fdir_filter_count; 204 + spinlock_t fdir_perfect_lock; /* spinlock for FDIR */ 340 205 }; 341 206 342 207 #endif /* _TXGBE_TYPE_H_ */