770-16-net-ethernet-mediatek-mtk_eth_soc-add-flow-offloadin.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. From: Felix Fietkau <[email protected]>
  2. Date: Sun, 11 Oct 2020 22:28:32 +0200
  3. Subject: [PATCH] net: ethernet: mediatek: mtk_eth_soc: add flow offloading
  4. support
  5. Only supports IPv4 for now
  6. Signed-off-by: Felix Fietkau <[email protected]>
  7. ---
  8. create mode 100644 drivers/net/ethernet/mediatek/mtk_offload.c
  9. create mode 100644 drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
  10. --- a/drivers/net/ethernet/mediatek/Makefile
  11. +++ b/drivers/net/ethernet/mediatek/Makefile
  12. @@ -4,4 +4,4 @@
  13. #
  14. obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
  15. -mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o
  16. +mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_offload.o
  17. --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
  18. +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
  19. @@ -19,6 +19,8 @@
  20. #include <linux/interrupt.h>
  21. #include <linux/pinctrl/devinfo.h>
  22. #include <linux/phylink.h>
  23. +#include <linux/netfilter.h>
  24. +#include <net/netfilter/nf_flow_table.h>
  25. #include <net/dsa.h>
  26. #include "mtk_eth_soc.h"
  27. @@ -1324,8 +1326,12 @@ static int mtk_poll_rx(struct napi_struc
  28. (trxd.rxd2 & RX_DMA_VTAG))
  29. __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
  30. RX_DMA_VID(trxd.rxd3));
  31. - skb_record_rx_queue(skb, 0);
  32. - napi_gro_receive(napi, skb);
  33. + if (mtk_offload_check_rx(eth, skb, trxd.rxd4) == 0) {
  34. + skb_record_rx_queue(skb, 0);
  35. + napi_gro_receive(napi, skb);
  36. + } else {
  37. + dev_kfree_skb(skb);
  38. + }
  39. skip_rx:
  40. ring->data[idx] = new_data;
  41. @@ -2858,6 +2864,25 @@ static int mtk_set_rxnfc(struct net_devi
  42. return ret;
  43. }
  44. +static int
  45. +mtk_flow_offload(enum flow_offload_type type, struct flow_offload *flow,
  46. + struct flow_offload_hw_path *src,
  47. + struct flow_offload_hw_path *dest)
  48. +{
  49. + struct mtk_mac *mac = netdev_priv(src->dev);
  50. + struct mtk_eth *eth = mac->hw;
  51. +
  52. + if (!eth->soc->offload_version)
  53. + return -EINVAL;
  54. +
  55. + if (src->dev->base_addr != dest->dev->base_addr)
  56. + return -EINVAL;
  57. +
  58. + mac = netdev_priv(src->dev);
  59. +
  60. + return mtk_flow_offload_add(eth, type, flow, src, dest);
  61. +}
  62. +
  63. static const struct ethtool_ops mtk_ethtool_ops = {
  64. .get_link_ksettings = mtk_get_link_ksettings,
  65. .set_link_ksettings = mtk_set_link_ksettings,
  66. @@ -2889,6 +2914,7 @@ static const struct net_device_ops mtk_n
  67. #ifdef CONFIG_NET_POLL_CONTROLLER
  68. .ndo_poll_controller = mtk_poll_controller,
  69. #endif
  70. + .ndo_flow_offload = mtk_flow_offload,
  71. };
  72. static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
  73. @@ -3154,6 +3180,10 @@ static int mtk_probe(struct platform_dev
  74. eth->base + MTK_ETH_PPE_BASE, 2);
  75. if (err)
  76. goto err_free_dev;
  77. +
  78. + err = mtk_flow_offload_init(eth);
  79. + if (err)
  80. + goto err_free_dev;
  81. }
  82. for (i = 0; i < MTK_MAX_DEVS; i++) {
  83. --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
  84. +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
  85. @@ -929,6 +929,7 @@ struct mtk_eth {
  86. int ip_align;
  87. struct mtk_ppe ppe;
  88. + struct flow_offload __rcu **foe_flow_table;
  89. };
  90. /* struct mtk_mac - the structure that holds the info about the MACs of the
  91. @@ -973,4 +974,12 @@ int mtk_gmac_sgmii_path_setup(struct mtk
  92. int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id);
  93. int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id);
  94. +int mtk_flow_offload_init(struct mtk_eth *eth);
  95. +int mtk_flow_offload_add(struct mtk_eth *eth,
  96. + enum flow_offload_type type,
  97. + struct flow_offload *flow,
  98. + struct flow_offload_hw_path *src,
  99. + struct flow_offload_hw_path *dest);
  100. +int mtk_offload_check_rx(struct mtk_eth *eth, struct sk_buff *skb, u32 rxd4);
  101. +
  102. #endif /* MTK_ETH_H */
  103. --- /dev/null
  104. +++ b/drivers/net/ethernet/mediatek/mtk_offload.c
  105. @@ -0,0 +1,146 @@
  106. +/* This program is free software; you can redistribute it and/or modify
  107. + * it under the terms of the GNU General Public License as published by
  108. + * the Free Software Foundation; version 2 of the License
  109. + *
  110. + * This program is distributed in the hope that it will be useful,
  111. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  112. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  113. + * GNU General Public License for more details.
  114. + *
  115. + * Copyright (C) 2018 John Crispin <[email protected]>
  116. + */
  117. +
  118. +#include <net/netfilter/nf_flow_table.h>
  119. +#include "mtk_eth_soc.h"
  120. +
  121. +static int
  122. +mtk_offload_prepare_v4(struct mtk_eth *eth, struct mtk_foe_entry *entry,
  123. + struct flow_offload_tuple *s_tuple,
  124. + struct flow_offload_tuple *d_tuple,
  125. + struct flow_offload_hw_path *src,
  126. + struct flow_offload_hw_path *dest)
  127. +{
  128. + int dest_port = 1;
  129. +
  130. + if (dest->dev == eth->netdev[1])
  131. + dest_port = 2;
  132. +
  133. + mtk_foe_entry_prepare(entry, MTK_PPE_PKT_TYPE_IPV4_HNAPT, s_tuple->l4proto,
  134. + dest_port, dest->eth_src, dest->eth_dest);
  135. + mtk_foe_entry_set_ipv4_tuple(entry, false,
  136. + s_tuple->src_v4.s_addr, s_tuple->src_port,
  137. + s_tuple->dst_v4.s_addr, s_tuple->dst_port);
  138. + mtk_foe_entry_set_ipv4_tuple(entry, true,
  139. + d_tuple->dst_v4.s_addr, d_tuple->dst_port,
  140. + d_tuple->src_v4.s_addr, d_tuple->src_port);
  141. +
  142. + if (dest->flags & FLOW_OFFLOAD_PATH_PPPOE)
  143. + mtk_foe_entry_set_pppoe(entry, dest->pppoe_sid);
  144. +
  145. + if (dest->flags & FLOW_OFFLOAD_PATH_VLAN)
  146. + mtk_foe_entry_set_vlan(entry, dest->vlan_id);
  147. +
  148. + if (dest->flags & FLOW_OFFLOAD_PATH_DSA)
  149. + mtk_foe_entry_set_dsa(entry, dest->dsa_port);
  150. +
  151. + return 0;
  152. +}
  153. +
  154. +int mtk_flow_offload_add(struct mtk_eth *eth,
  155. + enum flow_offload_type type,
  156. + struct flow_offload *flow,
  157. + struct flow_offload_hw_path *src,
  158. + struct flow_offload_hw_path *dest)
  159. +{
  160. + struct flow_offload_tuple *otuple = &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple;
  161. + struct flow_offload_tuple *rtuple = &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple;
  162. + struct mtk_foe_entry orig, reply;
  163. + u32 ohash, rhash, timestamp;
  164. +
  165. + if (otuple->l4proto != IPPROTO_TCP && otuple->l4proto != IPPROTO_UDP)
  166. + return -EINVAL;
  167. +
  168. + if (type == FLOW_OFFLOAD_DEL) {
  169. + ohash = (unsigned long)flow->priv;
  170. + rhash = ohash >> 16;
  171. + ohash &= 0xffff;
  172. + mtk_foe_entry_clear(&eth->ppe, ohash);
  173. + mtk_foe_entry_clear(&eth->ppe, rhash);
  174. + rcu_assign_pointer(eth->foe_flow_table[ohash], NULL);
  175. + rcu_assign_pointer(eth->foe_flow_table[rhash], NULL);
  176. + synchronize_rcu();
  177. +
  178. + return 0;
  179. + }
  180. +
  181. + switch (otuple->l3proto) {
  182. + case AF_INET:
  183. + if (mtk_offload_prepare_v4(eth, &orig, otuple, rtuple, src, dest) ||
  184. + mtk_offload_prepare_v4(eth, &reply, rtuple, otuple, dest, src))
  185. + return -EINVAL;
  186. + break;
  187. + default:
  188. + return -EINVAL;
  189. + }
  190. +
  191. + timestamp = mtk_r32(eth, 0x0010);
  192. +
  193. + ohash = mtk_foe_entry_commit(&eth->ppe, &orig, timestamp);
  194. + if (ohash < 0)
  195. + return -EINVAL;
  196. +
  197. + rhash = mtk_foe_entry_commit(&eth->ppe, &reply, timestamp);
  198. + if (rhash < 0) {
  199. + mtk_foe_entry_clear(&eth->ppe, ohash);
  200. + return -EINVAL;
  201. + }
  202. +
  203. + rcu_assign_pointer(eth->foe_flow_table[ohash], flow);
  204. + rcu_assign_pointer(eth->foe_flow_table[rhash], flow);
  205. +
  206. + ohash |= rhash << 16;
  207. + flow->priv = (void *)(unsigned long)ohash;
  208. +
  209. + return 0;
  210. +}
  211. +
  212. +static void mtk_offload_keepalive(struct mtk_eth *eth, unsigned int hash)
  213. +{
  214. + struct flow_offload *flow;
  215. +
  216. + rcu_read_lock();
  217. + flow = rcu_dereference(eth->foe_flow_table[hash]);
  218. + if (flow)
  219. + flow->timeout = jiffies + 30 * HZ;
  220. + rcu_read_unlock();
  221. +}
  222. +
  223. +int mtk_offload_check_rx(struct mtk_eth *eth, struct sk_buff *skb, u32 rxd4)
  224. +{
  225. + unsigned int hash;
  226. +
  227. + switch (FIELD_GET(MTK_RXD4_PPE_CPU_REASON, rxd4)) {
  228. + case MTK_PPE_CPU_REASON_KEEPALIVE_UC_OLD_HDR:
  229. + case MTK_PPE_CPU_REASON_KEEPALIVE_MC_NEW_HDR:
  230. + case MTK_PPE_CPU_REASON_KEEPALIVE_DUP_OLD_HDR:
  231. + hash = FIELD_GET(MTK_RXD4_FOE_ENTRY, rxd4);
  232. + mtk_offload_keepalive(eth, hash);
  233. + return -1;
  234. + case MTK_PPE_CPU_REASON_PACKET_SAMPLING:
  235. + return -1;
  236. + default:
  237. + return 0;
  238. + }
  239. +}
  240. +
  241. +int mtk_flow_offload_init(struct mtk_eth *eth)
  242. +{
  243. + eth->foe_flow_table = devm_kcalloc(eth->dev, MTK_PPE_ENTRIES,
  244. + sizeof(*eth->foe_flow_table),
  245. + GFP_KERNEL);
  246. +
  247. + if (!eth->foe_flow_table)
  248. + return -ENOMEM;
  249. +
  250. + return 0;
  251. +}
  252. --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
  253. +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
  254. @@ -375,6 +375,8 @@ int mtk_ppe_init(struct mtk_ppe *ppe, st
  255. ppe->foe_table = foe;
  256. + mtk_ppe_debugfs_init(ppe);
  257. +
  258. return 0;
  259. }
  260. --- a/drivers/net/ethernet/mediatek/mtk_ppe.h
  261. +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
  262. @@ -271,4 +271,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_f
  263. int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
  264. u16 timestamp);
  265. +/* internal */
  266. +int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
  267. +
  268. #endif
  269. --- /dev/null
  270. +++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
  271. @@ -0,0 +1,114 @@
  272. +/* This program is free software; you can redistribute it and/or modify
  273. + * it under the terms of the GNU General Public License as published by
  274. + * the Free Software Foundation; version 2 of the License
  275. + *
  276. + * This program is distributed in the hope that it will be useful,
  277. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  278. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  279. + * GNU General Public License for more details.
  280. + *
  281. + * Copyright (C) 2014-2016 Sean Wang <[email protected]>
  282. + * Copyright (C) 2016-2017 John Crispin <[email protected]>
  283. + * Copyright (C) 2020 Felix Fietkau <[email protected]>
  284. + */
  285. +
  286. +#include <linux/kernel.h>
  287. +#include <linux/debugfs.h>
  288. +#include "mtk_eth_soc.h"
  289. +
  290. +static const char *mtk_foe_entry_state_str[] = {
  291. + "INVALID",
  292. + "UNBIND",
  293. + "BIND",
  294. + "FIN"
  295. +};
  296. +
  297. +static const char *mtk_foe_packet_type_str[] = {
  298. + "IPV4_HNAPT",
  299. + "IPV4_HNAT",
  300. + "IPV6_1T_ROUTE",
  301. + "IPV4_DSLITE",
  302. + "IPV6_3T_ROUTE",
  303. + "IPV6_5T_ROUTE",
  304. + "IPV6_6RD",
  305. +};
  306. +
  307. +#define es(entry) (mtk_foe_entry_state_str[FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1)])
  308. +//#define ei(entry, end) (MTK_PPE_TBL_SZ - (int)(end - entry))
  309. +#define pt(entry) (mtk_foe_packet_type_str[FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1)])
  310. +
  311. +static int mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private)
  312. +{
  313. + struct mtk_ppe *ppe = m->private;
  314. + int i, count;
  315. +
  316. + for (i = 0, count = 0; i < MTK_PPE_ENTRIES; i++) {
  317. + struct mtk_foe_entry *entry = &ppe->foe_table[i];
  318. +
  319. + if (!FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1))
  320. + continue;
  321. +
  322. + if (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1) ==
  323. + MTK_PPE_PKT_TYPE_IPV4_HNAPT) {
  324. + struct mtk_foe_ipv4 *ip4 = &entry->ipv4;
  325. + struct mtk_foe_mac_info *l2 = &ip4->l2;
  326. +
  327. + __be32 saddr = htonl(ip4->orig.src_ip);
  328. + __be32 daddr = htonl(ip4->orig.dest_ip);
  329. + __be32 nsaddr = htonl(ip4->new.src_ip);
  330. + __be32 ndaddr = htonl(ip4->new.dest_ip);
  331. + unsigned char h_dest[ETH_ALEN];
  332. + unsigned char h_source[ETH_ALEN];
  333. +
  334. + *((__be32 *) h_source) = htonl(l2->src_mac_hi);
  335. + *((__be16*) &h_source[4]) = htons(l2->src_mac_lo);
  336. + *((__be32*) h_dest) = htonl(l2->dest_mac_hi);
  337. + *((__be16*) &h_dest[4]) = htons(l2->dest_mac_lo);
  338. + seq_printf(m,
  339. + "(%x)0x%05x|state=%s|type=%s|"
  340. + "%pI4:%d->%pI4:%d=>%pI4:%d->%pI4:%d|%pM=>%pM|"
  341. + "etype=0x%04x|info1=0x%x|info2=0x%x|"
  342. + "vlan1=%d|vlan2=%d\n",
  343. + count, i, es(entry), pt(entry),
  344. + &saddr, ip4->orig.src_port,
  345. + &daddr, ip4->orig.dest_port,
  346. + &nsaddr, ip4->new.src_port,
  347. + &ndaddr, ip4->new.dest_port,
  348. + h_source, h_dest,
  349. + ntohs(l2->etype),
  350. + entry->ib1,
  351. + ip4->ib2,
  352. + l2->vlan1,
  353. + l2->vlan2);
  354. + count++;
  355. + } else
  356. + seq_printf(m, "0x%05x state=%s\n", count, es(entry));
  357. + }
  358. +
  359. + return 0;
  360. +}
  361. +
  362. +static int mtk_ppe_debugfs_foe_open(struct inode *inode, struct file *file)
  363. +{
  364. + return single_open(file, mtk_ppe_debugfs_foe_show, inode->i_private);
  365. +}
  366. +
  367. +static const struct file_operations mtk_ppe_debugfs_foe_fops = {
  368. + .open = mtk_ppe_debugfs_foe_open,
  369. + .read = seq_read,
  370. + .llseek = seq_lseek,
  371. + .release = single_release,
  372. +};
  373. +
  374. +int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
  375. +{
  376. + struct dentry *root;
  377. +
  378. + root = debugfs_create_dir("mtk_ppe", NULL);
  379. + if (!root)
  380. + return -ENOMEM;
  381. +
  382. + debugfs_create_file("entries", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_fops);
  383. +
  384. + return 0;
  385. +}