txgbe_ethtool.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
  3. #include <linux/pci.h>
  4. #include <linux/phylink.h>
  5. #include <linux/netdevice.h>
  6. #include "../libwx/wx_ethtool.h"
  7. #include "../libwx/wx_type.h"
  8. #include "../libwx/wx_lib.h"
  9. #include "txgbe_type.h"
  10. #include "txgbe_fdir.h"
  11. #include "txgbe_ethtool.h"
  12. static int txgbe_set_ringparam(struct net_device *netdev,
  13. struct ethtool_ringparam *ring,
  14. struct kernel_ethtool_ringparam *kernel_ring,
  15. struct netlink_ext_ack *extack)
  16. {
  17. struct wx *wx = netdev_priv(netdev);
  18. u32 new_rx_count, new_tx_count;
  19. struct wx_ring *temp_ring;
  20. int i, err = 0;
  21. new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
  22. new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
  23. new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
  24. new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
  25. if (new_tx_count == wx->tx_ring_count &&
  26. new_rx_count == wx->rx_ring_count)
  27. return 0;
  28. err = wx_set_state_reset(wx);
  29. if (err)
  30. return err;
  31. if (!netif_running(wx->netdev)) {
  32. for (i = 0; i < wx->num_tx_queues; i++)
  33. wx->tx_ring[i]->count = new_tx_count;
  34. for (i = 0; i < wx->num_rx_queues; i++)
  35. wx->rx_ring[i]->count = new_rx_count;
  36. wx->tx_ring_count = new_tx_count;
  37. wx->rx_ring_count = new_rx_count;
  38. goto clear_reset;
  39. }
  40. /* allocate temporary buffer to store rings in */
  41. i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
  42. temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
  43. if (!temp_ring) {
  44. err = -ENOMEM;
  45. goto clear_reset;
  46. }
  47. txgbe_down(wx);
  48. wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
  49. kvfree(temp_ring);
  50. txgbe_up(wx);
  51. clear_reset:
  52. clear_bit(WX_STATE_RESETTING, wx->state);
  53. return err;
  54. }
  55. static int txgbe_set_channels(struct net_device *dev,
  56. struct ethtool_channels *ch)
  57. {
  58. int err;
  59. err = wx_set_channels(dev, ch);
  60. if (err < 0)
  61. return err;
  62. /* use setup TC to update any traffic class queue mapping */
  63. return txgbe_setup_tc(dev, netdev_get_num_tc(dev));
  64. }
  65. static int txgbe_get_ethtool_fdir_entry(struct txgbe *txgbe,
  66. struct ethtool_rxnfc *cmd)
  67. {
  68. struct ethtool_rx_flow_spec *fsp =
  69. (struct ethtool_rx_flow_spec *)&cmd->fs;
  70. union txgbe_atr_input *mask = &txgbe->fdir_mask;
  71. struct txgbe_fdir_filter *rule = NULL;
  72. struct hlist_node *node;
  73. /* report total rule count */
  74. cmd->data = (1024 << TXGBE_FDIR_PBALLOC_64K) - 2;
  75. hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list,
  76. fdir_node) {
  77. if (fsp->location <= rule->sw_idx)
  78. break;
  79. }
  80. if (!rule || fsp->location != rule->sw_idx)
  81. return -EINVAL;
  82. /* set flow type field */
  83. switch (rule->filter.formatted.flow_type) {
  84. case TXGBE_ATR_FLOW_TYPE_TCPV4:
  85. fsp->flow_type = TCP_V4_FLOW;
  86. break;
  87. case TXGBE_ATR_FLOW_TYPE_UDPV4:
  88. fsp->flow_type = UDP_V4_FLOW;
  89. break;
  90. case TXGBE_ATR_FLOW_TYPE_SCTPV4:
  91. fsp->flow_type = SCTP_V4_FLOW;
  92. break;
  93. case TXGBE_ATR_FLOW_TYPE_IPV4:
  94. fsp->flow_type = IP_USER_FLOW;
  95. fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
  96. fsp->h_u.usr_ip4_spec.proto = 0;
  97. fsp->m_u.usr_ip4_spec.proto = 0;
  98. break;
  99. default:
  100. return -EINVAL;
  101. }
  102. fsp->h_u.tcp_ip4_spec.psrc = rule->filter.formatted.src_port;
  103. fsp->m_u.tcp_ip4_spec.psrc = mask->formatted.src_port;
  104. fsp->h_u.tcp_ip4_spec.pdst = rule->filter.formatted.dst_port;
  105. fsp->m_u.tcp_ip4_spec.pdst = mask->formatted.dst_port;
  106. fsp->h_u.tcp_ip4_spec.ip4src = rule->filter.formatted.src_ip[0];
  107. fsp->m_u.tcp_ip4_spec.ip4src = mask->formatted.src_ip[0];
  108. fsp->h_u.tcp_ip4_spec.ip4dst = rule->filter.formatted.dst_ip[0];
  109. fsp->m_u.tcp_ip4_spec.ip4dst = mask->formatted.dst_ip[0];
  110. fsp->h_ext.vlan_etype = rule->filter.formatted.flex_bytes;
  111. fsp->m_ext.vlan_etype = mask->formatted.flex_bytes;
  112. fsp->h_ext.data[1] = htonl(rule->filter.formatted.vm_pool);
  113. fsp->m_ext.data[1] = htonl(mask->formatted.vm_pool);
  114. fsp->flow_type |= FLOW_EXT;
  115. /* record action */
  116. if (rule->action == TXGBE_RDB_FDIR_DROP_QUEUE)
  117. fsp->ring_cookie = RX_CLS_FLOW_DISC;
  118. else
  119. fsp->ring_cookie = rule->action;
  120. return 0;
  121. }
  122. static int txgbe_get_ethtool_fdir_all(struct txgbe *txgbe,
  123. struct ethtool_rxnfc *cmd,
  124. u32 *rule_locs)
  125. {
  126. struct txgbe_fdir_filter *rule;
  127. struct hlist_node *node;
  128. int cnt = 0;
  129. /* report total rule count */
  130. cmd->data = (1024 << TXGBE_FDIR_PBALLOC_64K) - 2;
  131. hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list,
  132. fdir_node) {
  133. if (cnt == cmd->rule_cnt)
  134. return -EMSGSIZE;
  135. rule_locs[cnt] = rule->sw_idx;
  136. cnt++;
  137. }
  138. cmd->rule_cnt = cnt;
  139. return 0;
  140. }
  141. static int txgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
  142. u32 *rule_locs)
  143. {
  144. struct wx *wx = netdev_priv(dev);
  145. struct txgbe *txgbe = wx->priv;
  146. int ret = -EOPNOTSUPP;
  147. switch (cmd->cmd) {
  148. case ETHTOOL_GRXRINGS:
  149. cmd->data = wx->num_rx_queues;
  150. ret = 0;
  151. break;
  152. case ETHTOOL_GRXCLSRLCNT:
  153. cmd->rule_cnt = txgbe->fdir_filter_count;
  154. ret = 0;
  155. break;
  156. case ETHTOOL_GRXCLSRULE:
  157. ret = txgbe_get_ethtool_fdir_entry(txgbe, cmd);
  158. break;
  159. case ETHTOOL_GRXCLSRLALL:
  160. ret = txgbe_get_ethtool_fdir_all(txgbe, cmd, (u32 *)rule_locs);
  161. break;
  162. default:
  163. break;
  164. }
  165. return ret;
  166. }
  167. static int txgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp,
  168. u8 *flow_type)
  169. {
  170. switch (fsp->flow_type & ~FLOW_EXT) {
  171. case TCP_V4_FLOW:
  172. *flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4;
  173. break;
  174. case UDP_V4_FLOW:
  175. *flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4;
  176. break;
  177. case SCTP_V4_FLOW:
  178. *flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4;
  179. break;
  180. case IP_USER_FLOW:
  181. switch (fsp->h_u.usr_ip4_spec.proto) {
  182. case IPPROTO_TCP:
  183. *flow_type = TXGBE_ATR_FLOW_TYPE_TCPV4;
  184. break;
  185. case IPPROTO_UDP:
  186. *flow_type = TXGBE_ATR_FLOW_TYPE_UDPV4;
  187. break;
  188. case IPPROTO_SCTP:
  189. *flow_type = TXGBE_ATR_FLOW_TYPE_SCTPV4;
  190. break;
  191. case 0:
  192. if (!fsp->m_u.usr_ip4_spec.proto) {
  193. *flow_type = TXGBE_ATR_FLOW_TYPE_IPV4;
  194. break;
  195. }
  196. fallthrough;
  197. default:
  198. return -EINVAL;
  199. }
  200. break;
  201. default:
  202. return -EINVAL;
  203. }
  204. return 0;
  205. }
  206. static bool txgbe_match_ethtool_fdir_entry(struct txgbe *txgbe,
  207. struct txgbe_fdir_filter *input)
  208. {
  209. struct txgbe_fdir_filter *rule = NULL;
  210. struct hlist_node *node2;
  211. hlist_for_each_entry_safe(rule, node2, &txgbe->fdir_filter_list,
  212. fdir_node) {
  213. if (rule->filter.formatted.bkt_hash ==
  214. input->filter.formatted.bkt_hash &&
  215. rule->action == input->action) {
  216. wx_dbg(txgbe->wx, "FDIR entry already exist\n");
  217. return true;
  218. }
  219. }
  220. return false;
  221. }
  222. static int txgbe_update_ethtool_fdir_entry(struct txgbe *txgbe,
  223. struct txgbe_fdir_filter *input,
  224. u16 sw_idx)
  225. {
  226. struct hlist_node *node = NULL, *parent = NULL;
  227. struct txgbe_fdir_filter *rule;
  228. struct wx *wx = txgbe->wx;
  229. bool deleted = false;
  230. int err;
  231. hlist_for_each_entry_safe(rule, node, &txgbe->fdir_filter_list,
  232. fdir_node) {
  233. /* hash found, or no matching entry */
  234. if (rule->sw_idx >= sw_idx)
  235. break;
  236. parent = node;
  237. }
  238. /* if there is an old rule occupying our place remove it */
  239. if (rule && rule->sw_idx == sw_idx) {
  240. /* hardware filters are only configured when interface is up,
  241. * and we should not issue filter commands while the interface
  242. * is down
  243. */
  244. if (netif_running(wx->netdev) &&
  245. (!input || rule->filter.formatted.bkt_hash !=
  246. input->filter.formatted.bkt_hash)) {
  247. err = txgbe_fdir_erase_perfect_filter(wx,
  248. &rule->filter,
  249. sw_idx);
  250. if (err)
  251. return -EINVAL;
  252. }
  253. hlist_del(&rule->fdir_node);
  254. kfree(rule);
  255. txgbe->fdir_filter_count--;
  256. deleted = true;
  257. }
  258. /* If we weren't given an input, then this was a request to delete a
  259. * filter. We should return -EINVAL if the filter wasn't found, but
  260. * return 0 if the rule was successfully deleted.
  261. */
  262. if (!input)
  263. return deleted ? 0 : -EINVAL;
  264. /* initialize node and set software index */
  265. INIT_HLIST_NODE(&input->fdir_node);
  266. /* add filter to the list */
  267. if (parent)
  268. hlist_add_behind(&input->fdir_node, parent);
  269. else
  270. hlist_add_head(&input->fdir_node,
  271. &txgbe->fdir_filter_list);
  272. /* update counts */
  273. txgbe->fdir_filter_count++;
  274. return 0;
  275. }
  276. static int txgbe_add_ethtool_fdir_entry(struct txgbe *txgbe,
  277. struct ethtool_rxnfc *cmd)
  278. {
  279. struct ethtool_rx_flow_spec *fsp =
  280. (struct ethtool_rx_flow_spec *)&cmd->fs;
  281. struct txgbe_fdir_filter *input;
  282. union txgbe_atr_input mask;
  283. struct wx *wx = txgbe->wx;
  284. int err = -EINVAL;
  285. u16 ptype = 0;
  286. u8 queue;
  287. if (!(test_bit(WX_FLAG_FDIR_PERFECT, wx->flags)))
  288. return -EOPNOTSUPP;
  289. /* ring_cookie is a masked into a set of queues and txgbe pools or
  290. * we use drop index
  291. */
  292. if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
  293. queue = TXGBE_RDB_FDIR_DROP_QUEUE;
  294. } else {
  295. u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
  296. if (ring >= wx->num_rx_queues)
  297. return -EINVAL;
  298. /* Map the ring onto the absolute queue index */
  299. queue = wx->rx_ring[ring]->reg_idx;
  300. }
  301. /* Don't allow indexes to exist outside of available space */
  302. if (fsp->location >= ((1024 << TXGBE_FDIR_PBALLOC_64K) - 2)) {
  303. wx_err(wx, "Location out of range\n");
  304. return -EINVAL;
  305. }
  306. input = kzalloc(sizeof(*input), GFP_ATOMIC);
  307. if (!input)
  308. return -ENOMEM;
  309. memset(&mask, 0, sizeof(union txgbe_atr_input));
  310. /* set SW index */
  311. input->sw_idx = fsp->location;
  312. /* record flow type */
  313. if (txgbe_flowspec_to_flow_type(fsp,
  314. &input->filter.formatted.flow_type)) {
  315. wx_err(wx, "Unrecognized flow type\n");
  316. goto err_out;
  317. }
  318. mask.formatted.flow_type = TXGBE_ATR_L4TYPE_IPV6_MASK |
  319. TXGBE_ATR_L4TYPE_MASK;
  320. if (input->filter.formatted.flow_type == TXGBE_ATR_FLOW_TYPE_IPV4)
  321. mask.formatted.flow_type &= TXGBE_ATR_L4TYPE_IPV6_MASK;
  322. /* Copy input into formatted structures */
  323. input->filter.formatted.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
  324. mask.formatted.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
  325. input->filter.formatted.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
  326. mask.formatted.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
  327. input->filter.formatted.src_port = fsp->h_u.tcp_ip4_spec.psrc;
  328. mask.formatted.src_port = fsp->m_u.tcp_ip4_spec.psrc;
  329. input->filter.formatted.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
  330. mask.formatted.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
  331. if (fsp->flow_type & FLOW_EXT) {
  332. input->filter.formatted.vm_pool =
  333. (unsigned char)ntohl(fsp->h_ext.data[1]);
  334. mask.formatted.vm_pool =
  335. (unsigned char)ntohl(fsp->m_ext.data[1]);
  336. input->filter.formatted.flex_bytes =
  337. fsp->h_ext.vlan_etype;
  338. mask.formatted.flex_bytes = fsp->m_ext.vlan_etype;
  339. }
  340. switch (input->filter.formatted.flow_type) {
  341. case TXGBE_ATR_FLOW_TYPE_TCPV4:
  342. ptype = WX_PTYPE_L2_IPV4_TCP;
  343. break;
  344. case TXGBE_ATR_FLOW_TYPE_UDPV4:
  345. ptype = WX_PTYPE_L2_IPV4_UDP;
  346. break;
  347. case TXGBE_ATR_FLOW_TYPE_SCTPV4:
  348. ptype = WX_PTYPE_L2_IPV4_SCTP;
  349. break;
  350. case TXGBE_ATR_FLOW_TYPE_IPV4:
  351. ptype = WX_PTYPE_L2_IPV4;
  352. break;
  353. default:
  354. break;
  355. }
  356. input->filter.formatted.vlan_id = htons(ptype);
  357. if (mask.formatted.flow_type & TXGBE_ATR_L4TYPE_MASK)
  358. mask.formatted.vlan_id = htons(0xFFFF);
  359. else
  360. mask.formatted.vlan_id = htons(0xFFF8);
  361. /* determine if we need to drop or route the packet */
  362. if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
  363. input->action = TXGBE_RDB_FDIR_DROP_QUEUE;
  364. else
  365. input->action = fsp->ring_cookie;
  366. spin_lock(&txgbe->fdir_perfect_lock);
  367. if (hlist_empty(&txgbe->fdir_filter_list)) {
  368. /* save mask and program input mask into HW */
  369. memcpy(&txgbe->fdir_mask, &mask, sizeof(mask));
  370. err = txgbe_fdir_set_input_mask(wx, &mask);
  371. if (err)
  372. goto err_unlock;
  373. } else if (memcmp(&txgbe->fdir_mask, &mask, sizeof(mask))) {
  374. wx_err(wx, "Hardware only supports one mask per port. To change the mask you must first delete all the rules.\n");
  375. goto err_unlock;
  376. }
  377. /* apply mask and compute/store hash */
  378. txgbe_atr_compute_perfect_hash(&input->filter, &mask);
  379. /* check if new entry does not exist on filter list */
  380. if (txgbe_match_ethtool_fdir_entry(txgbe, input))
  381. goto err_unlock;
  382. /* only program filters to hardware if the net device is running, as
  383. * we store the filters in the Rx buffer which is not allocated when
  384. * the device is down
  385. */
  386. if (netif_running(wx->netdev)) {
  387. err = txgbe_fdir_write_perfect_filter(wx, &input->filter,
  388. input->sw_idx, queue);
  389. if (err)
  390. goto err_unlock;
  391. }
  392. txgbe_update_ethtool_fdir_entry(txgbe, input, input->sw_idx);
  393. spin_unlock(&txgbe->fdir_perfect_lock);
  394. return 0;
  395. err_unlock:
  396. spin_unlock(&txgbe->fdir_perfect_lock);
  397. err_out:
  398. kfree(input);
  399. return err;
  400. }
  401. static int txgbe_del_ethtool_fdir_entry(struct txgbe *txgbe,
  402. struct ethtool_rxnfc *cmd)
  403. {
  404. struct ethtool_rx_flow_spec *fsp =
  405. (struct ethtool_rx_flow_spec *)&cmd->fs;
  406. int err = 0;
  407. spin_lock(&txgbe->fdir_perfect_lock);
  408. err = txgbe_update_ethtool_fdir_entry(txgbe, NULL, fsp->location);
  409. spin_unlock(&txgbe->fdir_perfect_lock);
  410. return err;
  411. }
  412. static int txgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
  413. {
  414. struct wx *wx = netdev_priv(dev);
  415. struct txgbe *txgbe = wx->priv;
  416. int ret = -EOPNOTSUPP;
  417. switch (cmd->cmd) {
  418. case ETHTOOL_SRXCLSRLINS:
  419. ret = txgbe_add_ethtool_fdir_entry(txgbe, cmd);
  420. break;
  421. case ETHTOOL_SRXCLSRLDEL:
  422. ret = txgbe_del_ethtool_fdir_entry(txgbe, cmd);
  423. break;
  424. default:
  425. break;
  426. }
  427. return ret;
  428. }
  429. static const struct ethtool_ops txgbe_ethtool_ops = {
  430. .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
  431. ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
  432. .get_drvinfo = wx_get_drvinfo,
  433. .nway_reset = wx_nway_reset,
  434. .get_link = ethtool_op_get_link,
  435. .get_link_ksettings = wx_get_link_ksettings,
  436. .set_link_ksettings = wx_set_link_ksettings,
  437. .get_sset_count = wx_get_sset_count,
  438. .get_strings = wx_get_strings,
  439. .get_ethtool_stats = wx_get_ethtool_stats,
  440. .get_eth_mac_stats = wx_get_mac_stats,
  441. .get_pause_stats = wx_get_pause_stats,
  442. .get_pauseparam = wx_get_pauseparam,
  443. .set_pauseparam = wx_set_pauseparam,
  444. .get_ringparam = wx_get_ringparam,
  445. .set_ringparam = txgbe_set_ringparam,
  446. .get_coalesce = wx_get_coalesce,
  447. .set_coalesce = wx_set_coalesce,
  448. .get_channels = wx_get_channels,
  449. .set_channels = txgbe_set_channels,
  450. .get_rxnfc = txgbe_get_rxnfc,
  451. .set_rxnfc = txgbe_set_rxnfc,
  452. .get_msglevel = wx_get_msglevel,
  453. .set_msglevel = wx_set_msglevel,
  454. };
  455. void txgbe_set_ethtool_ops(struct net_device *netdev)
  456. {
  457. netdev->ethtool_ops = &txgbe_ethtool_ops;
  458. }