tsnep_rxnfc.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (C) 2022 Gerhard Engleder <[email protected]> */
  3. #include "tsnep.h"
  4. #define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
  5. static void tsnep_enable_rule(struct tsnep_adapter *adapter,
  6. struct tsnep_rxnfc_rule *rule)
  7. {
  8. u8 rx_assign;
  9. void __iomem *addr;
  10. rx_assign = TSNEP_RX_ASSIGN_ACTIVE;
  11. rx_assign |= (rule->queue_index << TSNEP_RX_ASSIGN_QUEUE_SHIFT) &
  12. TSNEP_RX_ASSIGN_QUEUE_MASK;
  13. addr = adapter->addr + TSNEP_RX_ASSIGN_ETHER_TYPE +
  14. TSNEP_RX_ASSIGN_ETHER_TYPE_OFFSET * rule->location;
  15. iowrite16(rule->filter.ether_type, addr);
  16. /* enable rule after all settings are done */
  17. addr = adapter->addr + TSNEP_RX_ASSIGN +
  18. TSNEP_RX_ASSIGN_OFFSET * rule->location;
  19. iowrite8(rx_assign, addr);
  20. }
  21. static void tsnep_disable_rule(struct tsnep_adapter *adapter,
  22. struct tsnep_rxnfc_rule *rule)
  23. {
  24. void __iomem *addr;
  25. addr = adapter->addr + TSNEP_RX_ASSIGN +
  26. TSNEP_RX_ASSIGN_OFFSET * rule->location;
  27. iowrite8(0, addr);
  28. }
  29. static struct tsnep_rxnfc_rule *tsnep_get_rule(struct tsnep_adapter *adapter,
  30. int location)
  31. {
  32. struct tsnep_rxnfc_rule *rule;
  33. list_for_each_entry(rule, &adapter->rxnfc_rules, list) {
  34. if (rule->location == location)
  35. return rule;
  36. if (rule->location > location)
  37. break;
  38. }
  39. return NULL;
  40. }
  41. static void tsnep_add_rule(struct tsnep_adapter *adapter,
  42. struct tsnep_rxnfc_rule *rule)
  43. {
  44. struct tsnep_rxnfc_rule *pred, *cur;
  45. tsnep_enable_rule(adapter, rule);
  46. pred = NULL;
  47. list_for_each_entry(cur, &adapter->rxnfc_rules, list) {
  48. if (cur->location >= rule->location)
  49. break;
  50. pred = cur;
  51. }
  52. list_add(&rule->list, pred ? &pred->list : &adapter->rxnfc_rules);
  53. adapter->rxnfc_count++;
  54. }
  55. static void tsnep_delete_rule(struct tsnep_adapter *adapter,
  56. struct tsnep_rxnfc_rule *rule)
  57. {
  58. tsnep_disable_rule(adapter, rule);
  59. list_del(&rule->list);
  60. adapter->rxnfc_count--;
  61. kfree(rule);
  62. }
  63. static void tsnep_flush_rules(struct tsnep_adapter *adapter)
  64. {
  65. struct tsnep_rxnfc_rule *rule, *tmp;
  66. mutex_lock(&adapter->rxnfc_lock);
  67. list_for_each_entry_safe(rule, tmp, &adapter->rxnfc_rules, list)
  68. tsnep_delete_rule(adapter, rule);
  69. mutex_unlock(&adapter->rxnfc_lock);
  70. }
  71. int tsnep_rxnfc_get_rule(struct tsnep_adapter *adapter,
  72. struct ethtool_rxnfc *cmd)
  73. {
  74. struct ethtool_rx_flow_spec *fsp = &cmd->fs;
  75. struct tsnep_rxnfc_rule *rule = NULL;
  76. cmd->data = adapter->rxnfc_max;
  77. mutex_lock(&adapter->rxnfc_lock);
  78. rule = tsnep_get_rule(adapter, fsp->location);
  79. if (!rule) {
  80. mutex_unlock(&adapter->rxnfc_lock);
  81. return -ENOENT;
  82. }
  83. fsp->flow_type = ETHER_FLOW;
  84. fsp->ring_cookie = rule->queue_index;
  85. if (rule->filter.type == TSNEP_RXNFC_ETHER_TYPE) {
  86. fsp->h_u.ether_spec.h_proto = htons(rule->filter.ether_type);
  87. fsp->m_u.ether_spec.h_proto = ETHER_TYPE_FULL_MASK;
  88. }
  89. mutex_unlock(&adapter->rxnfc_lock);
  90. return 0;
  91. }
  92. int tsnep_rxnfc_get_all(struct tsnep_adapter *adapter,
  93. struct ethtool_rxnfc *cmd,
  94. u32 *rule_locs)
  95. {
  96. struct tsnep_rxnfc_rule *rule;
  97. int count = 0;
  98. cmd->data = adapter->rxnfc_max;
  99. mutex_lock(&adapter->rxnfc_lock);
  100. list_for_each_entry(rule, &adapter->rxnfc_rules, list) {
  101. if (count == cmd->rule_cnt) {
  102. mutex_unlock(&adapter->rxnfc_lock);
  103. return -EMSGSIZE;
  104. }
  105. rule_locs[count] = rule->location;
  106. count++;
  107. }
  108. mutex_unlock(&adapter->rxnfc_lock);
  109. cmd->rule_cnt = count;
  110. return 0;
  111. }
  112. static int tsnep_rxnfc_find_location(struct tsnep_adapter *adapter)
  113. {
  114. struct tsnep_rxnfc_rule *tmp;
  115. int location = 0;
  116. list_for_each_entry(tmp, &adapter->rxnfc_rules, list) {
  117. if (tmp->location == location)
  118. location++;
  119. else
  120. return location;
  121. }
  122. if (location >= adapter->rxnfc_max)
  123. return -ENOSPC;
  124. return location;
  125. }
  126. static void tsnep_rxnfc_init_rule(struct tsnep_rxnfc_rule *rule,
  127. const struct ethtool_rx_flow_spec *fsp)
  128. {
  129. INIT_LIST_HEAD(&rule->list);
  130. rule->queue_index = fsp->ring_cookie;
  131. rule->location = fsp->location;
  132. rule->filter.type = TSNEP_RXNFC_ETHER_TYPE;
  133. rule->filter.ether_type = ntohs(fsp->h_u.ether_spec.h_proto);
  134. }
  135. static int tsnep_rxnfc_check_rule(struct tsnep_adapter *adapter,
  136. struct tsnep_rxnfc_rule *rule)
  137. {
  138. struct net_device *dev = adapter->netdev;
  139. struct tsnep_rxnfc_rule *tmp;
  140. list_for_each_entry(tmp, &adapter->rxnfc_rules, list) {
  141. if (!memcmp(&rule->filter, &tmp->filter, sizeof(rule->filter)) &&
  142. tmp->location != rule->location) {
  143. netdev_dbg(dev, "rule already exists\n");
  144. return -EEXIST;
  145. }
  146. }
  147. return 0;
  148. }
  149. int tsnep_rxnfc_add_rule(struct tsnep_adapter *adapter,
  150. struct ethtool_rxnfc *cmd)
  151. {
  152. struct net_device *netdev = adapter->netdev;
  153. struct ethtool_rx_flow_spec *fsp =
  154. (struct ethtool_rx_flow_spec *)&cmd->fs;
  155. struct tsnep_rxnfc_rule *rule, *old_rule;
  156. int retval;
  157. /* only EtherType is supported */
  158. if (fsp->flow_type != ETHER_FLOW ||
  159. !is_zero_ether_addr(fsp->m_u.ether_spec.h_dest) ||
  160. !is_zero_ether_addr(fsp->m_u.ether_spec.h_source) ||
  161. fsp->m_u.ether_spec.h_proto != ETHER_TYPE_FULL_MASK) {
  162. netdev_dbg(netdev, "only ethernet protocol is supported\n");
  163. return -EOPNOTSUPP;
  164. }
  165. if (fsp->ring_cookie >
  166. (TSNEP_RX_ASSIGN_QUEUE_MASK >> TSNEP_RX_ASSIGN_QUEUE_SHIFT)) {
  167. netdev_dbg(netdev, "invalid action\n");
  168. return -EINVAL;
  169. }
  170. if (fsp->location != RX_CLS_LOC_ANY &&
  171. fsp->location >= adapter->rxnfc_max) {
  172. netdev_dbg(netdev, "invalid location\n");
  173. return -EINVAL;
  174. }
  175. rule = kzalloc(sizeof(*rule), GFP_KERNEL);
  176. if (!rule)
  177. return -ENOMEM;
  178. mutex_lock(&adapter->rxnfc_lock);
  179. if (fsp->location == RX_CLS_LOC_ANY) {
  180. retval = tsnep_rxnfc_find_location(adapter);
  181. if (retval < 0)
  182. goto failed;
  183. fsp->location = retval;
  184. }
  185. tsnep_rxnfc_init_rule(rule, fsp);
  186. retval = tsnep_rxnfc_check_rule(adapter, rule);
  187. if (retval)
  188. goto failed;
  189. old_rule = tsnep_get_rule(adapter, fsp->location);
  190. if (old_rule)
  191. tsnep_delete_rule(adapter, old_rule);
  192. tsnep_add_rule(adapter, rule);
  193. mutex_unlock(&adapter->rxnfc_lock);
  194. return 0;
  195. failed:
  196. mutex_unlock(&adapter->rxnfc_lock);
  197. kfree(rule);
  198. return retval;
  199. }
  200. int tsnep_rxnfc_del_rule(struct tsnep_adapter *adapter,
  201. struct ethtool_rxnfc *cmd)
  202. {
  203. struct ethtool_rx_flow_spec *fsp =
  204. (struct ethtool_rx_flow_spec *)&cmd->fs;
  205. struct tsnep_rxnfc_rule *rule;
  206. mutex_lock(&adapter->rxnfc_lock);
  207. rule = tsnep_get_rule(adapter, fsp->location);
  208. if (!rule) {
  209. mutex_unlock(&adapter->rxnfc_lock);
  210. return -ENOENT;
  211. }
  212. tsnep_delete_rule(adapter, rule);
  213. mutex_unlock(&adapter->rxnfc_lock);
  214. return 0;
  215. }
  216. int tsnep_rxnfc_init(struct tsnep_adapter *adapter)
  217. {
  218. int i;
  219. /* disable all rules */
  220. for (i = 0; i < adapter->rxnfc_max;
  221. i += sizeof(u32) / TSNEP_RX_ASSIGN_OFFSET)
  222. iowrite32(0, adapter->addr + TSNEP_RX_ASSIGN + i);
  223. return 0;
  224. }
  225. void tsnep_rxnfc_cleanup(struct tsnep_adapter *adapter)
  226. {
  227. tsnep_flush_rules(adapter);
  228. }