rtl8366-core.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Realtek SMI library helpers for the RTL8366x variants
  3. * RTL8366RB and RTL8366S
  4. *
  5. * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
  6. * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
  7. * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
  8. * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv>
  9. * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
  10. */
  11. #include <linux/if_bridge.h>
  12. #include <net/dsa.h>
  13. #include "realtek.h"
  14. int rtl8366_mc_is_used(struct realtek_priv *priv, int mc_index, int *used)
  15. {
  16. int ret;
  17. int i;
  18. *used = 0;
  19. for (i = 0; i < priv->num_ports; i++) {
  20. int index = 0;
  21. ret = priv->ops->get_mc_index(priv, i, &index);
  22. if (ret)
  23. return ret;
  24. if (mc_index == index) {
  25. *used = 1;
  26. break;
  27. }
  28. }
  29. return 0;
  30. }
  31. EXPORT_SYMBOL_NS_GPL(rtl8366_mc_is_used, "REALTEK_DSA");
  32. /**
  33. * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration
  34. * @priv: the Realtek SMI device instance
  35. * @vid: the VLAN ID to look up or allocate
  36. * @vlanmc: the pointer will be assigned to a pointer to a valid member config
  37. * if successful
  38. * @return: index of a new member config or negative error number
  39. */
  40. static int rtl8366_obtain_mc(struct realtek_priv *priv, int vid,
  41. struct rtl8366_vlan_mc *vlanmc)
  42. {
  43. struct rtl8366_vlan_4k vlan4k;
  44. int ret;
  45. int i;
  46. /* Try to find an existing member config entry for this VID */
  47. for (i = 0; i < priv->num_vlan_mc; i++) {
  48. ret = priv->ops->get_vlan_mc(priv, i, vlanmc);
  49. if (ret) {
  50. dev_err(priv->dev, "error searching for VLAN MC %d for VID %d\n",
  51. i, vid);
  52. return ret;
  53. }
  54. if (vid == vlanmc->vid)
  55. return i;
  56. }
  57. /* We have no MC entry for this VID, try to find an empty one */
  58. for (i = 0; i < priv->num_vlan_mc; i++) {
  59. ret = priv->ops->get_vlan_mc(priv, i, vlanmc);
  60. if (ret) {
  61. dev_err(priv->dev, "error searching for VLAN MC %d for VID %d\n",
  62. i, vid);
  63. return ret;
  64. }
  65. if (vlanmc->vid == 0 && vlanmc->member == 0) {
  66. /* Update the entry from the 4K table */
  67. ret = priv->ops->get_vlan_4k(priv, vid, &vlan4k);
  68. if (ret) {
  69. dev_err(priv->dev, "error looking for 4K VLAN MC %d for VID %d\n",
  70. i, vid);
  71. return ret;
  72. }
  73. vlanmc->vid = vid;
  74. vlanmc->member = vlan4k.member;
  75. vlanmc->untag = vlan4k.untag;
  76. vlanmc->fid = vlan4k.fid;
  77. ret = priv->ops->set_vlan_mc(priv, i, vlanmc);
  78. if (ret) {
  79. dev_err(priv->dev, "unable to set/update VLAN MC %d for VID %d\n",
  80. i, vid);
  81. return ret;
  82. }
  83. dev_dbg(priv->dev, "created new MC at index %d for VID %d\n",
  84. i, vid);
  85. return i;
  86. }
  87. }
  88. /* MC table is full, try to find an unused entry and replace it */
  89. for (i = 0; i < priv->num_vlan_mc; i++) {
  90. int used;
  91. ret = rtl8366_mc_is_used(priv, i, &used);
  92. if (ret)
  93. return ret;
  94. if (!used) {
  95. /* Update the entry from the 4K table */
  96. ret = priv->ops->get_vlan_4k(priv, vid, &vlan4k);
  97. if (ret)
  98. return ret;
  99. vlanmc->vid = vid;
  100. vlanmc->member = vlan4k.member;
  101. vlanmc->untag = vlan4k.untag;
  102. vlanmc->fid = vlan4k.fid;
  103. ret = priv->ops->set_vlan_mc(priv, i, vlanmc);
  104. if (ret) {
  105. dev_err(priv->dev, "unable to set/update VLAN MC %d for VID %d\n",
  106. i, vid);
  107. return ret;
  108. }
  109. dev_dbg(priv->dev, "recycled MC at index %i for VID %d\n",
  110. i, vid);
  111. return i;
  112. }
  113. }
  114. dev_err(priv->dev, "all VLAN member configurations are in use\n");
  115. return -ENOSPC;
  116. }
  117. int rtl8366_set_vlan(struct realtek_priv *priv, int vid, u32 member,
  118. u32 untag, u32 fid)
  119. {
  120. struct rtl8366_vlan_mc vlanmc;
  121. struct rtl8366_vlan_4k vlan4k;
  122. int mc;
  123. int ret;
  124. if (!priv->ops->is_vlan_valid(priv, vid))
  125. return -EINVAL;
  126. dev_dbg(priv->dev,
  127. "setting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n",
  128. vid, member, untag);
  129. /* Update the 4K table */
  130. ret = priv->ops->get_vlan_4k(priv, vid, &vlan4k);
  131. if (ret)
  132. return ret;
  133. vlan4k.member |= member;
  134. vlan4k.untag |= untag;
  135. vlan4k.fid = fid;
  136. ret = priv->ops->set_vlan_4k(priv, &vlan4k);
  137. if (ret)
  138. return ret;
  139. dev_dbg(priv->dev,
  140. "resulting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n",
  141. vid, vlan4k.member, vlan4k.untag);
  142. /* Find or allocate a member config for this VID */
  143. ret = rtl8366_obtain_mc(priv, vid, &vlanmc);
  144. if (ret < 0)
  145. return ret;
  146. mc = ret;
  147. /* Update the MC entry */
  148. vlanmc.member |= member;
  149. vlanmc.untag |= untag;
  150. vlanmc.fid = fid;
  151. /* Commit updates to the MC entry */
  152. ret = priv->ops->set_vlan_mc(priv, mc, &vlanmc);
  153. if (ret)
  154. dev_err(priv->dev, "failed to commit changes to VLAN MC index %d for VID %d\n",
  155. mc, vid);
  156. else
  157. dev_dbg(priv->dev,
  158. "resulting VLAN%d MC members: 0x%02x, untagged: 0x%02x\n",
  159. vid, vlanmc.member, vlanmc.untag);
  160. return ret;
  161. }
  162. EXPORT_SYMBOL_NS_GPL(rtl8366_set_vlan, "REALTEK_DSA");
  163. int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port,
  164. unsigned int vid)
  165. {
  166. struct rtl8366_vlan_mc vlanmc;
  167. int mc;
  168. int ret;
  169. if (!priv->ops->is_vlan_valid(priv, vid))
  170. return -EINVAL;
  171. /* Find or allocate a member config for this VID */
  172. ret = rtl8366_obtain_mc(priv, vid, &vlanmc);
  173. if (ret < 0)
  174. return ret;
  175. mc = ret;
  176. ret = priv->ops->set_mc_index(priv, port, mc);
  177. if (ret) {
  178. dev_err(priv->dev, "set PVID: failed to set MC index %d for port %d\n",
  179. mc, port);
  180. return ret;
  181. }
  182. dev_dbg(priv->dev, "set PVID: the PVID for port %d set to %d using existing MC index %d\n",
  183. port, vid, mc);
  184. return 0;
  185. }
  186. EXPORT_SYMBOL_NS_GPL(rtl8366_set_pvid, "REALTEK_DSA");
  187. int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable)
  188. {
  189. int ret;
  190. /* To enable 4k VLAN, ordinary VLAN must be enabled first,
  191. * but if we disable 4k VLAN it is fine to leave ordinary
  192. * VLAN enabled.
  193. */
  194. if (enable) {
  195. /* Make sure VLAN is ON */
  196. ret = priv->ops->enable_vlan(priv, true);
  197. if (ret)
  198. return ret;
  199. priv->vlan_enabled = true;
  200. }
  201. ret = priv->ops->enable_vlan4k(priv, enable);
  202. if (ret)
  203. return ret;
  204. priv->vlan4k_enabled = enable;
  205. return 0;
  206. }
  207. EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan4k, "REALTEK_DSA");
  208. int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable)
  209. {
  210. int ret;
  211. ret = priv->ops->enable_vlan(priv, enable);
  212. if (ret)
  213. return ret;
  214. priv->vlan_enabled = enable;
  215. /* If we turn VLAN off, make sure that we turn off
  216. * 4k VLAN as well, if that happened to be on.
  217. */
  218. if (!enable) {
  219. priv->vlan4k_enabled = false;
  220. ret = priv->ops->enable_vlan4k(priv, false);
  221. }
  222. return ret;
  223. }
  224. EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan, "REALTEK_DSA");
  225. int rtl8366_reset_vlan(struct realtek_priv *priv)
  226. {
  227. struct rtl8366_vlan_mc vlanmc;
  228. int ret;
  229. int i;
  230. rtl8366_enable_vlan(priv, false);
  231. rtl8366_enable_vlan4k(priv, false);
  232. /* Clear the 16 VLAN member configurations */
  233. vlanmc.vid = 0;
  234. vlanmc.priority = 0;
  235. vlanmc.member = 0;
  236. vlanmc.untag = 0;
  237. vlanmc.fid = 0;
  238. for (i = 0; i < priv->num_vlan_mc; i++) {
  239. ret = priv->ops->set_vlan_mc(priv, i, &vlanmc);
  240. if (ret)
  241. return ret;
  242. }
  243. return 0;
  244. }
  245. EXPORT_SYMBOL_NS_GPL(rtl8366_reset_vlan, "REALTEK_DSA");
  246. int rtl8366_vlan_add(struct dsa_switch *ds, int port,
  247. const struct switchdev_obj_port_vlan *vlan,
  248. struct netlink_ext_ack *extack)
  249. {
  250. bool untagged = !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
  251. bool pvid = !!(vlan->flags & BRIDGE_VLAN_INFO_PVID);
  252. struct realtek_priv *priv = ds->priv;
  253. u32 member = 0;
  254. u32 untag = 0;
  255. int ret;
  256. if (!priv->ops->is_vlan_valid(priv, vlan->vid)) {
  257. NL_SET_ERR_MSG_MOD(extack, "VLAN ID not valid");
  258. return -EINVAL;
  259. }
  260. /* Enable VLAN in the hardware
  261. * FIXME: what's with this 4k business?
  262. * Just rtl8366_enable_vlan() seems inconclusive.
  263. */
  264. ret = rtl8366_enable_vlan4k(priv, true);
  265. if (ret) {
  266. NL_SET_ERR_MSG_MOD(extack, "Failed to enable VLAN 4K");
  267. return ret;
  268. }
  269. dev_dbg(priv->dev, "add VLAN %d on port %d, %s, %s\n",
  270. vlan->vid, port, untagged ? "untagged" : "tagged",
  271. pvid ? "PVID" : "no PVID");
  272. member |= BIT(port);
  273. if (untagged)
  274. untag |= BIT(port);
  275. ret = rtl8366_set_vlan(priv, vlan->vid, member, untag, 0);
  276. if (ret) {
  277. dev_err(priv->dev, "failed to set up VLAN %04x", vlan->vid);
  278. return ret;
  279. }
  280. if (!pvid)
  281. return 0;
  282. ret = rtl8366_set_pvid(priv, port, vlan->vid);
  283. if (ret) {
  284. dev_err(priv->dev, "failed to set PVID on port %d to VLAN %04x",
  285. port, vlan->vid);
  286. return ret;
  287. }
  288. return 0;
  289. }
  290. EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_add, "REALTEK_DSA");
  291. int rtl8366_vlan_del(struct dsa_switch *ds, int port,
  292. const struct switchdev_obj_port_vlan *vlan)
  293. {
  294. struct realtek_priv *priv = ds->priv;
  295. int ret, i;
  296. dev_dbg(priv->dev, "del VLAN %d on port %d\n", vlan->vid, port);
  297. for (i = 0; i < priv->num_vlan_mc; i++) {
  298. struct rtl8366_vlan_mc vlanmc;
  299. ret = priv->ops->get_vlan_mc(priv, i, &vlanmc);
  300. if (ret)
  301. return ret;
  302. if (vlan->vid == vlanmc.vid) {
  303. /* Remove this port from the VLAN */
  304. vlanmc.member &= ~BIT(port);
  305. vlanmc.untag &= ~BIT(port);
  306. /*
  307. * If no ports are members of this VLAN
  308. * anymore then clear the whole member
  309. * config so it can be reused.
  310. */
  311. if (!vlanmc.member) {
  312. vlanmc.vid = 0;
  313. vlanmc.priority = 0;
  314. vlanmc.fid = 0;
  315. }
  316. ret = priv->ops->set_vlan_mc(priv, i, &vlanmc);
  317. if (ret) {
  318. dev_err(priv->dev,
  319. "failed to remove VLAN %04x\n",
  320. vlan->vid);
  321. return ret;
  322. }
  323. break;
  324. }
  325. }
  326. return 0;
  327. }
  328. EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_del, "REALTEK_DSA");
  329. void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset,
  330. uint8_t *data)
  331. {
  332. struct realtek_priv *priv = ds->priv;
  333. int i;
  334. if (port >= priv->num_ports)
  335. return;
  336. for (i = 0; i < priv->num_mib_counters; i++)
  337. ethtool_puts(&data, priv->mib_counters[i].name);
  338. }
  339. EXPORT_SYMBOL_NS_GPL(rtl8366_get_strings, "REALTEK_DSA");
  340. int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset)
  341. {
  342. struct realtek_priv *priv = ds->priv;
  343. /* We only support SS_STATS */
  344. if (sset != ETH_SS_STATS)
  345. return 0;
  346. if (port >= priv->num_ports)
  347. return -EINVAL;
  348. return priv->num_mib_counters;
  349. }
  350. EXPORT_SYMBOL_NS_GPL(rtl8366_get_sset_count, "REALTEK_DSA");
  351. void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
  352. {
  353. struct realtek_priv *priv = ds->priv;
  354. int i;
  355. int ret;
  356. if (port >= priv->num_ports)
  357. return;
  358. for (i = 0; i < priv->num_mib_counters; i++) {
  359. struct rtl8366_mib_counter *mib;
  360. u64 mibvalue = 0;
  361. mib = &priv->mib_counters[i];
  362. ret = priv->ops->get_mib_counter(priv, port, mib, &mibvalue);
  363. if (ret) {
  364. dev_err(priv->dev, "error reading MIB counter %s\n",
  365. mib->name);
  366. }
  367. data[i] = mibvalue;
  368. }
  369. }
  370. EXPORT_SYMBOL_NS_GPL(rtl8366_get_ethtool_stats, "REALTEK_DSA");