rtl930x.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <asm/mach-rtl838x/mach-rtl83xx.h>
  3. #include "rtl83xx.h"
  4. extern struct mutex smi_lock;
  5. extern struct rtl83xx_soc_info soc_info;
  6. void rtl930x_print_matrix(void)
  7. {
  8. int i;
  9. struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6);
  10. for (i = 0; i < 29; i++) {
  11. rtl_table_read(r, i);
  12. pr_debug("> %08x\n", sw_r32(rtl_table_data(r, 0)));
  13. }
  14. rtl_table_release(r);
  15. }
  16. inline void rtl930x_exec_tbl0_cmd(u32 cmd)
  17. {
  18. sw_w32(cmd, RTL930X_TBL_ACCESS_CTRL_0);
  19. do { } while (sw_r32(RTL930X_TBL_ACCESS_CTRL_0) & (1 << 17));
  20. }
  21. inline void rtl930x_exec_tbl1_cmd(u32 cmd)
  22. {
  23. sw_w32(cmd, RTL930X_TBL_ACCESS_CTRL_1);
  24. do { } while (sw_r32(RTL930X_TBL_ACCESS_CTRL_1) & (1 << 17));
  25. }
  26. inline int rtl930x_tbl_access_data_0(int i)
  27. {
  28. return RTL930X_TBL_ACCESS_DATA_0(i);
  29. }
  30. static inline int rtl930x_l2_port_new_salrn(int p)
  31. {
  32. return RTL930X_L2_PORT_SALRN(p);
  33. }
  34. static inline int rtl930x_l2_port_new_sa_fwd(int p)
  35. {
  36. // TODO: The definition of the fields changed, because of the master-cpu in a stack
  37. return RTL930X_L2_PORT_NEW_SA_FWD(p);
  38. }
  39. inline static int rtl930x_trk_mbr_ctr(int group)
  40. {
  41. return RTL930X_TRK_MBR_CTRL + (group << 2);
  42. }
  43. static void rtl930x_vlan_tables_read(u32 vlan, struct rtl838x_vlan_info *info)
  44. {
  45. u32 v, w;
  46. // Read VLAN table (1) via register 0
  47. struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 1);
  48. rtl_table_read(r, vlan);
  49. v = sw_r32(rtl_table_data(r, 0));
  50. w = sw_r32(rtl_table_data(r, 1));
  51. pr_debug("VLAN_READ %d: %08x %08x\n", vlan, v, w);
  52. rtl_table_release(r);
  53. info->tagged_ports = v >> 3;
  54. info->profile_id = (w >> 24) & 7;
  55. info->hash_mc_fid = !!(w & BIT(27));
  56. info->hash_uc_fid = !!(w & BIT(28));
  57. info->fid = ((v & 0x7) << 3) | ((w >> 29) & 0x7);
  58. // Read UNTAG table via table register 2
  59. r = rtl_table_get(RTL9300_TBL_2, 0);
  60. rtl_table_read(r, vlan);
  61. v = sw_r32(rtl_table_data(r, 0));
  62. rtl_table_release(r);
  63. info->untagged_ports = v >> 3;
  64. }
  65. static void rtl930x_vlan_set_tagged(u32 vlan, struct rtl838x_vlan_info *info)
  66. {
  67. u32 v, w;
  68. // Access VLAN table (1) via register 0
  69. struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 1);
  70. v = info->tagged_ports << 3;
  71. v |= ((u32)info->fid) >> 3;
  72. w = ((u32)info->fid) << 29;
  73. w |= info->hash_mc_fid ? BIT(27) : 0;
  74. w |= info->hash_uc_fid ? BIT(28) : 0;
  75. w |= info->profile_id << 24;
  76. sw_w32(v, rtl_table_data(r, 0));
  77. sw_w32(w, rtl_table_data(r, 1));
  78. rtl_table_write(r, vlan);
  79. rtl_table_release(r);
  80. }
  81. void rtl930x_vlan_profile_dump(int profile)
  82. {
  83. u32 p[5];
  84. if (profile < 0 || profile > 7)
  85. return;
  86. p[0] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile));
  87. p[1] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 4);
  88. p[2] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 8) & 0x1FFFFFFF;
  89. p[3] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 12) & 0x1FFFFFFF;
  90. p[4] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 16) & 0x1FFFFFFF;
  91. pr_info("VLAN %d: L2 learn: %d; Unknown MC PMasks: L2 %0x, IPv4 %0x, IPv6: %0x",
  92. profile, p[0] & (3 << 21), p[2], p[3], p[4]);
  93. pr_info(" Routing enabled: IPv4 UC %c, IPv6 UC %c, IPv4 MC %c, IPv6 MC %c\n",
  94. p[0] & BIT(17) ? 'y' : 'n', p[0] & BIT(16) ? 'y' : 'n',
  95. p[0] & BIT(13) ? 'y' : 'n', p[0] & BIT(12) ? 'y' : 'n');
  96. pr_info(" Bridge enabled: IPv4 MC %c, IPv6 MC %c,\n",
  97. p[0] & BIT(15) ? 'y' : 'n', p[0] & BIT(14) ? 'y' : 'n');
  98. pr_info("VLAN profile %d: raw %08x %08x %08x %08x %08x\n",
  99. profile, p[0], p[1], p[2], p[3], p[4]);
  100. }
  101. static void rtl930x_vlan_set_untagged(u32 vlan, u64 portmask)
  102. {
  103. struct table_reg *r = rtl_table_get(RTL9300_TBL_2, 0);
  104. sw_w32(portmask << 3, rtl_table_data(r, 0));
  105. rtl_table_write(r, vlan);
  106. rtl_table_release(r);
  107. }
  108. /* Sets the L2 forwarding to be based on either the inner VLAN tag or the outer
  109. */
  110. static void rtl930x_vlan_fwd_on_inner(int port, bool is_set)
  111. {
  112. // Always set all tag modes to fwd based on either inner or outer tag
  113. if (is_set)
  114. sw_w32_mask(0, 0xf, RTL930X_VLAN_PORT_FWD + (port << 2));
  115. else
  116. sw_w32_mask(0xf, 0, RTL930X_VLAN_PORT_FWD + (port << 2));
  117. }
  118. static void rtl930x_vlan_profile_setup(int profile)
  119. {
  120. u32 p[5];
  121. pr_info("In %s\n", __func__);
  122. p[0] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile));
  123. p[1] = sw_r32(RTL930X_VLAN_PROFILE_SET(profile) + 4);
  124. // Enable routing of Ipv4/6 Unicast and IPv4/6 Multicast traffic
  125. p[0] |= BIT(17) | BIT(16) | BIT(13) | BIT(12);
  126. p[2] = 0x1fffffff; // L2 unknown MC flooding portmask all ports, including the CPU-port
  127. p[3] = 0x1fffffff; // IPv4 unknown MC flooding portmask
  128. p[4] = 0x1fffffff; // IPv6 unknown MC flooding portmask
  129. sw_w32(p[0], RTL930X_VLAN_PROFILE_SET(profile));
  130. sw_w32(p[1], RTL930X_VLAN_PROFILE_SET(profile) + 4);
  131. sw_w32(p[2], RTL930X_VLAN_PROFILE_SET(profile) + 8);
  132. sw_w32(p[3], RTL930X_VLAN_PROFILE_SET(profile) + 12);
  133. sw_w32(p[4], RTL930X_VLAN_PROFILE_SET(profile) + 16);
  134. pr_info("Leaving %s\n", __func__);
  135. }
  136. static void rtl930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
  137. {
  138. int i;
  139. u32 cmd = 1 << 17 /* Execute cmd */
  140. | 0 << 16 /* Read */
  141. | 4 << 12 /* Table type 0b10 */
  142. | (msti & 0xfff);
  143. priv->r->exec_tbl0_cmd(cmd);
  144. for (i = 0; i < 2; i++)
  145. port_state[i] = sw_r32(RTL930X_TBL_ACCESS_DATA_0(i));
  146. pr_debug("MSTI: %d STATE: %08x, %08x\n", msti, port_state[0], port_state[1]);
  147. }
  148. static void rtl930x_stp_set(struct rtl838x_switch_priv *priv, u16 msti, u32 port_state[])
  149. {
  150. int i;
  151. u32 cmd = 1 << 17 /* Execute cmd */
  152. | 1 << 16 /* Write */
  153. | 4 << 12 /* Table type 4 */
  154. | (msti & 0xfff);
  155. for (i = 0; i < 2; i++)
  156. sw_w32(port_state[i], RTL930X_TBL_ACCESS_DATA_0(i));
  157. priv->r->exec_tbl0_cmd(cmd);
  158. }
  159. static inline int rtl930x_mac_force_mode_ctrl(int p)
  160. {
  161. return RTL930X_MAC_FORCE_MODE_CTRL + (p << 2);
  162. }
  163. static inline int rtl930x_mac_port_ctrl(int p)
  164. {
  165. return RTL930X_MAC_L2_PORT_CTRL(p);
  166. }
  167. static inline int rtl930x_mac_link_spd_sts(int p)
  168. {
  169. return RTL930X_MAC_LINK_SPD_STS(p);
  170. }
  171. static u64 rtl930x_l2_hash_seed(u64 mac, u32 vid)
  172. {
  173. u64 v = vid;
  174. v <<= 48;
  175. v |= mac;
  176. return v;
  177. }
  178. /*
  179. * Calculate both the block 0 and the block 1 hash by applyingthe same hash
  180. * algorithm as the one used currently by the ASIC to the seed, and return
  181. * both hashes in the lower and higher word of the return value since only 12 bit of
  182. * the hash are significant
  183. */
  184. static u32 rtl930x_l2_hash_key(struct rtl838x_switch_priv *priv, u64 seed)
  185. {
  186. u32 k0, k1, h1, h2, h;
  187. k0 = (u32) (((seed >> 55) & 0x1f) ^ ((seed >> 44) & 0x7ff)
  188. ^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff)
  189. ^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff));
  190. h1 = (seed >> 11) & 0x7ff;
  191. h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f);
  192. h2 = (seed >> 33) & 0x7ff;
  193. h2 = ((h2 & 0x3f) << 5)| ((h2 >> 6) & 0x3f);
  194. k1 = (u32) (((seed << 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) ^ h2
  195. ^ ((seed >> 22) & 0x7ff) ^ h1
  196. ^ (seed & 0x7ff));
  197. // Algorithm choice for block 0
  198. if (sw_r32(RTL930X_L2_CTRL) & BIT(0))
  199. h = k1;
  200. else
  201. h = k0;
  202. /* Algorithm choice for block 1
  203. * Since k0 and k1 are < 2048, adding 2048 will offset the hash into the second
  204. * half of hash-space
  205. * 2048 is in fact the hash-table size 16384 divided by 4 hashes per bucket
  206. * divided by 2 to divide the hash space in 2
  207. */
  208. if (sw_r32(RTL930X_L2_CTRL) & BIT(1))
  209. h |= (k1 + 2048) << 16;
  210. else
  211. h |= (k0 + 2048) << 16;
  212. return h;
  213. }
  214. /*
  215. * Fills an L2 entry structure from the SoC registers
  216. */
  217. static void rtl930x_fill_l2_entry(u32 r[], struct rtl838x_l2_entry *e)
  218. {
  219. pr_debug("In %s valid?\n", __func__);
  220. e->valid = !!(r[2] & BIT(31));
  221. if (!e->valid)
  222. return;
  223. pr_debug("In %s is valid\n", __func__);
  224. e->is_ip_mc = false;
  225. e->is_ipv6_mc = false;
  226. // TODO: Is there not a function to copy directly MAC memory?
  227. e->mac[0] = (r[0] >> 24);
  228. e->mac[1] = (r[0] >> 16);
  229. e->mac[2] = (r[0] >> 8);
  230. e->mac[3] = r[0];
  231. e->mac[4] = (r[1] >> 24);
  232. e->mac[5] = (r[1] >> 16);
  233. e->next_hop = !!(r[2] & BIT(12));
  234. e->rvid = r[1] & 0xfff;
  235. /* Is it a unicast entry? check multicast bit */
  236. if (!(e->mac[0] & 1)) {
  237. e->type = L2_UNICAST;
  238. e->is_static = !!(r[2] & BIT(14));
  239. e->port = (r[2] >> 20) & 0x3ff;
  240. // Check for trunk port
  241. if (r[2] & BIT(30)) {
  242. e->is_trunk = true;
  243. e->stack_dev = (e->port >> 9) & 1;
  244. e->trunk = e->port & 0x3f;
  245. } else {
  246. e->is_trunk = false;
  247. e->stack_dev = (e->port >> 6) & 0xf;
  248. e->port = e->port & 0x3f;
  249. }
  250. e->block_da = !!(r[2] & BIT(15));
  251. e->block_sa = !!(r[2] & BIT(16));
  252. e->suspended = !!(r[2] & BIT(13));
  253. e->age = (r[2] >> 17) & 3;
  254. e->valid = true;
  255. // the UC_VID field in hardware is used for the VID or for the route id
  256. if (e->next_hop) {
  257. e->nh_route_id = r[2] & 0xfff;
  258. e->vid = 0;
  259. } else {
  260. e->vid = r[2] & 0xfff;
  261. e->nh_route_id = 0;
  262. }
  263. } else {
  264. e->valid = true;
  265. e->type = L2_MULTICAST;
  266. e->mc_portmask_index = (r[2] >> 16) & 0x3ff;
  267. }
  268. }
  269. /*
  270. * Fills the 3 SoC table registers r[] with the information of in the rtl838x_l2_entry
  271. */
  272. static void rtl930x_fill_l2_row(u32 r[], struct rtl838x_l2_entry *e)
  273. {
  274. u32 port;
  275. if (!e->valid) {
  276. r[0] = r[1] = r[2] = 0;
  277. return;
  278. }
  279. r[2] = BIT(31); // Set valid bit
  280. r[0] = ((u32)e->mac[0]) << 24 | ((u32)e->mac[1]) << 16
  281. | ((u32)e->mac[2]) << 8 | ((u32)e->mac[3]);
  282. r[1] = ((u32)e->mac[4]) << 24 | ((u32)e->mac[5]) << 16;
  283. r[2] |= e->next_hop ? BIT(12) : 0;
  284. if (e->type == L2_UNICAST) {
  285. r[2] |= e->is_static ? BIT(14) : 0;
  286. r[1] |= e->rvid & 0xfff;
  287. r[2] |= (e->port & 0x3ff) << 20;
  288. if (e->is_trunk) {
  289. r[2] |= BIT(30);
  290. port = e->stack_dev << 9 | (e->port & 0x3f);
  291. } else {
  292. port = (e->stack_dev & 0xf) << 6;
  293. port |= e->port & 0x3f;
  294. }
  295. r[2] |= port << 20;
  296. r[2] |= e->block_da ? BIT(15) : 0;
  297. r[2] |= e->block_sa ? BIT(17) : 0;
  298. r[2] |= e->suspended ? BIT(13) : 0;
  299. r[2] |= (e->age & 0x3) << 17;
  300. // the UC_VID field in hardware is used for the VID or for the route id
  301. if (e->next_hop)
  302. r[2] |= e->nh_route_id & 0xfff;
  303. else
  304. r[2] |= e->vid & 0xfff;
  305. } else { // L2_MULTICAST
  306. r[2] |= (e->mc_portmask_index & 0x3ff) << 16;
  307. r[2] |= e->mc_mac_index & 0x7ff;
  308. }
  309. }
  310. /*
  311. * Read an L2 UC or MC entry out of a hash bucket of the L2 forwarding table
  312. * hash is the id of the bucket and pos is the position of the entry in that bucket
  313. * The data read from the SoC is filled into rtl838x_l2_entry
  314. */
  315. static u64 rtl930x_read_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e)
  316. {
  317. u32 r[3];
  318. struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 0);
  319. u32 idx;
  320. int i;
  321. u64 mac;
  322. u64 seed;
  323. pr_debug("%s: hash %08x, pos: %d\n", __func__, hash, pos);
  324. /* On the RTL93xx, 2 different hash algorithms are used making it a total of
  325. * 8 buckets that need to be searched, 4 for each hash-half
  326. * Use second hash space when bucket is between 4 and 8 */
  327. if (pos >= 4) {
  328. pos -= 4;
  329. hash >>= 16;
  330. } else {
  331. hash &= 0xffff;
  332. }
  333. idx = (0 << 14) | (hash << 2) | pos; // Search SRAM, with hash and at pos in bucket
  334. pr_debug("%s: NOW hash %08x, pos: %d\n", __func__, hash, pos);
  335. rtl_table_read(q, idx);
  336. for (i = 0; i < 3; i++)
  337. r[i] = sw_r32(rtl_table_data(q, i));
  338. rtl_table_release(q);
  339. rtl930x_fill_l2_entry(r, e);
  340. pr_debug("%s: valid: %d, nh: %d\n", __func__, e->valid, e->next_hop);
  341. if (!e->valid)
  342. return 0;
  343. mac = ((u64)e->mac[0]) << 40 | ((u64)e->mac[1]) << 32 | ((u64)e->mac[2]) << 24
  344. | ((u64)e->mac[3]) << 16 | ((u64)e->mac[4]) << 8 | ((u64)e->mac[5]);
  345. seed = rtl930x_l2_hash_seed(mac, e->rvid);
  346. pr_debug("%s: mac %016llx, seed %016llx\n", __func__, mac, seed);
  347. // return vid with concatenated mac as unique id
  348. return seed;
  349. }
  350. static void rtl930x_write_l2_entry_using_hash(u32 hash, u32 pos, struct rtl838x_l2_entry *e)
  351. {
  352. u32 r[3];
  353. struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 0);
  354. u32 idx = (0 << 14) | (hash << 2) | pos; // Access SRAM, with hash and at pos in bucket
  355. int i;
  356. pr_info("%s: hash %d, pos %d\n", __func__, hash, pos);
  357. pr_info("%s: index %d -> mac %02x:%02x:%02x:%02x:%02x:%02x\n", __func__, idx,
  358. e->mac[0], e->mac[1], e->mac[2], e->mac[3],e->mac[4],e->mac[5]);
  359. rtl930x_fill_l2_row(r, e);
  360. for (i= 0; i < 3; i++)
  361. sw_w32(r[i], rtl_table_data(q, i));
  362. rtl_table_write(q, idx);
  363. rtl_table_release(q);
  364. }
  365. static u64 rtl930x_read_cam(int idx, struct rtl838x_l2_entry *e)
  366. {
  367. u32 r[3];
  368. struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 1);
  369. int i;
  370. rtl_table_read(q, idx);
  371. for (i= 0; i < 3; i++)
  372. r[i] = sw_r32(rtl_table_data(q, i));
  373. rtl_table_release(q);
  374. rtl930x_fill_l2_entry(r, e);
  375. if (!e->valid)
  376. return 0;
  377. // return mac with concatenated vid as unique id
  378. return ((u64)r[0] << 28) | ((r[1] & 0xffff0000) >> 4) | e->vid;
  379. }
  380. static void rtl930x_write_cam(int idx, struct rtl838x_l2_entry *e)
  381. {
  382. u32 r[3];
  383. struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 1); // Access L2 Table 1
  384. int i;
  385. rtl930x_fill_l2_row(r, e);
  386. for (i= 0; i < 3; i++)
  387. sw_w32(r[i], rtl_table_data(q, i));
  388. rtl_table_write(q, idx);
  389. rtl_table_release(q);
  390. }
  391. static void dump_l2_entry(struct rtl838x_l2_entry *e)
  392. {
  393. pr_info("MAC: %02x:%02x:%02x:%02x:%02x:%02x vid: %d, rvid: %d, port: %d, valid: %d\n",
  394. e->mac[0], e->mac[1], e->mac[2], e->mac[3], e->mac[4], e->mac[5],
  395. e->vid, e->rvid, e->port, e->valid);
  396. pr_info("Type: %d, is_static: %d, is_ip_mc: %d, is_ipv6_mc: %d, block_da: %d\n",
  397. e->type, e->is_static, e->is_ip_mc, e->is_ipv6_mc, e->block_da);
  398. pr_info(" block_sa: %d, suspended: %d, next_hop: %d, age: %d, is_trunk: %d, trunk: %d\n",
  399. e->block_sa, e->suspended, e->next_hop, e->age, e->is_trunk, e->trunk);
  400. if (e->is_ip_mc || e->is_ipv6_mc)
  401. pr_info(" mc_portmask_index: %d, mc_gip: %d, mc_sip: %d\n",
  402. e->mc_portmask_index, e->mc_gip, e->mc_sip);
  403. pr_info(" stac_dev: %d, nh_route_id: %d, port: %d, dev_id\n",
  404. e->stack_dev, e->nh_route_id, e->port);
  405. }
  406. /*
  407. * Add an L2 nexthop entry for the L3 routing system in the SoC
  408. * Use VID and MAC in rtl838x_l2_entry to identify either a free slot in the L2 hash table
  409. * or mark an existing entry as a nexthop by setting it's nexthop bit
  410. * Called from the L3 layer
  411. * The index in the L2 hash table is filled into nh->l2_id;
  412. */
  413. static int rtl930x_l2_nexthop_add(struct rtl838x_switch_priv *priv, struct rtl838x_nexthop *nh)
  414. {
  415. struct rtl838x_l2_entry e;
  416. u64 seed = rtl930x_l2_hash_seed(nh->mac, nh->vid);
  417. u32 key = rtl930x_l2_hash_key(priv, seed);
  418. int i, idx = -1;
  419. u64 entry;
  420. pr_info("%s searching for %08llx vid %d with key %d, seed: %016llx\n",
  421. __func__, nh->mac, nh->vid, key, seed);
  422. e.type = L2_UNICAST;
  423. e.rvid = nh->fid; // Verify its the forwarding ID!!! l2_entry.un.unicast.fid
  424. u64_to_ether_addr(nh->mac, &e.mac[0]);
  425. e.port = RTL930X_PORT_IGNORE;
  426. // Loop over all entries in the hash-bucket and over the second block on 93xx SoCs
  427. for (i = 0; i < priv->l2_bucket_size; i++) {
  428. entry = rtl930x_read_l2_entry_using_hash(key, i, &e);
  429. pr_info("%s i: %d, entry %016llx, seed %016llx\n", __func__, i, entry, seed);
  430. if (e.valid && e.next_hop)
  431. continue;
  432. if (!e.valid || ((entry & 0x0fffffffffffffffULL) == seed)) {
  433. idx = i > 3 ? ((key >> 14) & 0xffff) | i >> 1
  434. : ((key << 2) | i) & 0xffff;
  435. break;
  436. }
  437. }
  438. pr_info("%s: found idx %d and i %d\n", __func__, idx, i);
  439. if (idx < 0) {
  440. pr_err("%s: No more L2 forwarding entries available\n", __func__);
  441. return -1;
  442. }
  443. // Found an existing or empty entry, make it a nexthop entry
  444. pr_info("%s BEFORE -> key %d, pos: %d, index: %d\n", __func__, key, i, idx);
  445. dump_l2_entry(&e);
  446. nh->l2_id = idx;
  447. // Found an existing (e->valid is true) or empty entry, make it a nexthop entry
  448. if (e.valid) {
  449. nh->port = e.port;
  450. nh->fid = e.rvid;
  451. nh->vid = e.vid;
  452. nh->dev_id = e.stack_dev;
  453. } else {
  454. e.valid = true;
  455. e.is_static = false;
  456. e.vid = nh->vid;
  457. e.rvid = nh->fid;
  458. e.port = RTL930X_PORT_IGNORE;
  459. u64_to_ether_addr(nh->mac, &e.mac[0]);
  460. }
  461. e.next_hop = true;
  462. // For nexthop entries, the vid field in the table is used to denote the dest mac_id
  463. e.nh_route_id = nh->mac_id;
  464. pr_info("%s AFTER\n", __func__);
  465. dump_l2_entry(&e);
  466. rtl930x_write_l2_entry_using_hash(idx >> 2, idx & 0x3, &e);
  467. // _dal_longan_l2_nexthop_add
  468. return 0;
  469. }
  470. static u64 rtl930x_read_mcast_pmask(int idx)
  471. {
  472. u32 portmask;
  473. // Read MC_PORTMASK (2) via register RTL9300_TBL_L2
  474. struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 2);
  475. rtl_table_read(q, idx);
  476. portmask = sw_r32(rtl_table_data(q, 0));
  477. portmask >>= 3;
  478. rtl_table_release(q);
  479. pr_debug("%s: Index idx %d has portmask %08x\n", __func__, idx, portmask);
  480. return portmask;
  481. }
  482. static void rtl930x_write_mcast_pmask(int idx, u64 portmask)
  483. {
  484. u32 pm = portmask;
  485. // Access MC_PORTMASK (2) via register RTL9300_TBL_L2
  486. struct table_reg *q = rtl_table_get(RTL9300_TBL_L2, 2);
  487. pr_debug("%s: Index idx %d has portmask %08x\n", __func__, idx, pm);
  488. pm <<= 3;
  489. sw_w32(pm, rtl_table_data(q, 0));
  490. rtl_table_write(q, idx);
  491. rtl_table_release(q);
  492. }
  493. u64 rtl930x_traffic_get(int source)
  494. {
  495. u32 v;
  496. struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6);
  497. rtl_table_read(r, source);
  498. v = sw_r32(rtl_table_data(r, 0));
  499. rtl_table_release(r);
  500. return v >> 3;
  501. }
  502. /*
  503. * Enable traffic between a source port and a destination port matrix
  504. */
  505. void rtl930x_traffic_set(int source, u64 dest_matrix)
  506. {
  507. struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6);
  508. sw_w32((dest_matrix << 3), rtl_table_data(r, 0));
  509. rtl_table_write(r, source);
  510. rtl_table_release(r);
  511. }
  512. void rtl930x_traffic_enable(int source, int dest)
  513. {
  514. struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6);
  515. rtl_table_read(r, source);
  516. sw_w32_mask(0, BIT(dest + 3), rtl_table_data(r, 0));
  517. rtl_table_write(r, source);
  518. rtl_table_release(r);
  519. }
  520. void rtl930x_traffic_disable(int source, int dest)
  521. {
  522. struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 6);
  523. rtl_table_read(r, source);
  524. sw_w32_mask(BIT(dest + 3), 0, rtl_table_data(r, 0));
  525. rtl_table_write(r, source);
  526. rtl_table_release(r);
  527. }
  528. void rtl9300_dump_debug(void)
  529. {
  530. int i;
  531. u16 r = RTL930X_STAT_PRVTE_DROP_COUNTER0;
  532. for (i = 0; i < 10; i ++) {
  533. pr_info("# %d %08x %08x %08x %08x %08x %08x %08x %08x\n", i * 8,
  534. sw_r32(r), sw_r32(r + 4), sw_r32(r + 8), sw_r32(r + 12),
  535. sw_r32(r + 16), sw_r32(r + 20), sw_r32(r + 24), sw_r32(r + 28));
  536. r += 32;
  537. }
  538. pr_info("# %08x %08x %08x %08x %08x\n",
  539. sw_r32(r), sw_r32(r + 4), sw_r32(r + 8), sw_r32(r + 12), sw_r32(r + 16));
  540. rtl930x_print_matrix();
  541. pr_info("RTL930X_L2_PORT_SABLK_CTRL: %08x, RTL930X_L2_PORT_DABLK_CTRL %08x\n",
  542. sw_r32(RTL930X_L2_PORT_SABLK_CTRL), sw_r32(RTL930X_L2_PORT_DABLK_CTRL)
  543. );
  544. }
  545. irqreturn_t rtl930x_switch_irq(int irq, void *dev_id)
  546. {
  547. struct dsa_switch *ds = dev_id;
  548. u32 status = sw_r32(RTL930X_ISR_GLB);
  549. u32 ports = sw_r32(RTL930X_ISR_PORT_LINK_STS_CHG);
  550. u32 link;
  551. int i;
  552. /* Clear status */
  553. sw_w32(ports, RTL930X_ISR_PORT_LINK_STS_CHG);
  554. pr_info("RTL9300 Link change: status: %x, ports %x\n", status, ports);
  555. rtl9300_dump_debug();
  556. for (i = 0; i < 28; i++) {
  557. if (ports & BIT(i)) {
  558. /* Read the register twice because of issues with latency at least
  559. * with the external RTL8226 PHY on the XGS1210 */
  560. link = sw_r32(RTL930X_MAC_LINK_STS);
  561. link = sw_r32(RTL930X_MAC_LINK_STS);
  562. if (link & BIT(i))
  563. dsa_port_phylink_mac_change(ds, i, true);
  564. else
  565. dsa_port_phylink_mac_change(ds, i, false);
  566. }
  567. }
  568. return IRQ_HANDLED;
  569. }
  570. int rtl9300_sds_power(int mac, int val)
  571. {
  572. int sds_num;
  573. u32 mode;
  574. // TODO: these numbers are hard-coded for the Zyxel XGS1210 12 Switch
  575. pr_info("SerDes: %s %d\n", __func__, mac);
  576. switch (mac) {
  577. case 24:
  578. sds_num = 6;
  579. mode = 0x12; // HISGMII
  580. break;
  581. case 25:
  582. sds_num = 7;
  583. mode = 0x12; // HISGMII
  584. break;
  585. case 26:
  586. sds_num = 8;
  587. mode = 0x1b; // 10GR/1000BX auto
  588. break;
  589. case 27:
  590. sds_num = 9;
  591. mode = 0x1b; // 10GR/1000BX auto
  592. break;
  593. default:
  594. return -1;
  595. }
  596. if (!val)
  597. mode = 0x1f; // OFF
  598. rtl9300_sds_rst(sds_num, mode);
  599. return 0;
  600. }
  601. int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val)
  602. {
  603. u32 v;
  604. int err = 0;
  605. pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, val);
  606. if (port > 63 || page > 4095 || reg > 31)
  607. return -ENOTSUPP;
  608. val &= 0xffff;
  609. mutex_lock(&smi_lock);
  610. sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0);
  611. sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
  612. v = reg << 20 | page << 3 | 0x1f << 15 | BIT(2) | BIT(0);
  613. sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
  614. do {
  615. v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
  616. } while (v & 0x1);
  617. if (v & 0x2)
  618. err = -EIO;
  619. mutex_unlock(&smi_lock);
  620. return err;
  621. }
  622. int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val)
  623. {
  624. u32 v;
  625. int err = 0;
  626. if (port > 63 || page > 4095 || reg > 31)
  627. return -ENOTSUPP;
  628. mutex_lock(&smi_lock);
  629. sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
  630. v = reg << 20 | page << 3 | 0x1f << 15 | 1;
  631. sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
  632. do {
  633. v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
  634. } while ( v & 0x1);
  635. if (v & BIT(25)) {
  636. pr_debug("Error reading phy %d, register %d\n", port, reg);
  637. err = -EIO;
  638. }
  639. *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff);
  640. pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, *val);
  641. mutex_unlock(&smi_lock);
  642. return err;
  643. }
  644. /*
  645. * Write to an mmd register of the PHY
  646. */
  647. int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val)
  648. {
  649. int err = 0;
  650. u32 v;
  651. mutex_lock(&smi_lock);
  652. // Set PHY to access
  653. sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0);
  654. // Set data to write
  655. sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
  656. // Set MMD device number and register to write to
  657. sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3);
  658. v = BIT(2) | BIT(1) | BIT(0); // WRITE | MMD-access | EXEC
  659. sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
  660. do {
  661. v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
  662. } while (v & BIT(0));
  663. pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err);
  664. mutex_unlock(&smi_lock);
  665. return err;
  666. }
  667. /*
  668. * Read an mmd register of the PHY
  669. */
  670. int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
  671. {
  672. int err = 0;
  673. u32 v;
  674. mutex_lock(&smi_lock);
  675. // Set PHY to access
  676. sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2);
  677. // Set MMD device number and register to write to
  678. sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3);
  679. v = BIT(1) | BIT(0); // MMD-access | EXEC
  680. sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1);
  681. do {
  682. v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1);
  683. } while (v & BIT(0));
  684. // There is no error-checking via BIT 25 of v, as it does not seem to be set correctly
  685. *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff);
  686. pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err);
  687. mutex_unlock(&smi_lock);
  688. return err;
  689. }
  690. /*
  691. * Calculate both the block 0 and the block 1 hash, and return in
  692. * lower and higher word of the return value since only 12 bit of
  693. * the hash are significant
  694. */
  695. u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed)
  696. {
  697. u32 k0, k1, h1, h2, h;
  698. k0 = (u32) (((seed >> 55) & 0x1f) ^ ((seed >> 44) & 0x7ff)
  699. ^ ((seed >> 33) & 0x7ff) ^ ((seed >> 22) & 0x7ff)
  700. ^ ((seed >> 11) & 0x7ff) ^ (seed & 0x7ff));
  701. h1 = (seed >> 11) & 0x7ff;
  702. h1 = ((h1 & 0x1f) << 6) | ((h1 >> 5) & 0x3f);
  703. h2 = (seed >> 33) & 0x7ff;
  704. h2 = ((h2 & 0x3f) << 5)| ((h2 >> 6) & 0x3f);
  705. k1 = (u32) (((seed << 55) & 0x1f) ^ ((seed >> 44) & 0x7ff) ^ h2
  706. ^ ((seed >> 22) & 0x7ff) ^ h1
  707. ^ (seed & 0x7ff));
  708. // Algorithm choice for block 0
  709. if (sw_r32(RTL930X_L2_CTRL) & BIT(0))
  710. h = k1;
  711. else
  712. h = k0;
  713. /* Algorithm choice for block 1
  714. * Since k0 and k1 are < 2048, adding 2048 will offset the hash into the second
  715. * half of hash-space
  716. * 2048 is in fact the hash-table size 16384 divided by 4 hashes per bucket
  717. * divided by 2 to divide the hash space in 2
  718. */
  719. if (sw_r32(RTL930X_L2_CTRL) & BIT(1))
  720. h |= (k1 + 2048) << 16;
  721. else
  722. h |= (k0 + 2048) << 16;
  723. return h;
  724. }
  725. /*
  726. * Enables or disables the EEE/EEEP capability of a port
  727. */
  728. void rtl930x_port_eee_set(struct rtl838x_switch_priv *priv, int port, bool enable)
  729. {
  730. u32 v;
  731. // This works only for Ethernet ports, and on the RTL930X, ports from 26 are SFP
  732. if (port >= 26)
  733. return;
  734. pr_debug("In %s: setting port %d to %d\n", __func__, port, enable);
  735. v = enable ? 0x3f : 0x0;
  736. // Set EEE/EEEP state for 100, 500, 1000MBit and 2.5, 5 and 10GBit
  737. sw_w32_mask(0, v << 10, rtl930x_mac_force_mode_ctrl(port));
  738. // Set TX/RX EEE state
  739. v = enable ? 0x3 : 0x0;
  740. sw_w32(v, RTL930X_EEE_CTRL(port));
  741. priv->ports[port].eee_enabled = enable;
  742. }
  743. /*
  744. * Get EEE own capabilities and negotiation result
  745. */
  746. int rtl930x_eee_port_ability(struct rtl838x_switch_priv *priv, struct ethtool_eee *e, int port)
  747. {
  748. u32 link, a;
  749. if (port >= 26)
  750. return -ENOTSUPP;
  751. pr_info("In %s, port %d\n", __func__, port);
  752. link = sw_r32(RTL930X_MAC_LINK_STS);
  753. link = sw_r32(RTL930X_MAC_LINK_STS);
  754. if (!(link & BIT(port)))
  755. return 0;
  756. pr_info("Setting advertised\n");
  757. if (sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(10))
  758. e->advertised |= ADVERTISED_100baseT_Full;
  759. if (sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(12))
  760. e->advertised |= ADVERTISED_1000baseT_Full;
  761. if (priv->ports[port].is2G5 && sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(13)) {
  762. pr_info("ADVERTISING 2.5G EEE\n");
  763. e->advertised |= ADVERTISED_2500baseX_Full;
  764. }
  765. if (priv->ports[port].is10G && sw_r32(rtl930x_mac_force_mode_ctrl(port)) & BIT(15))
  766. e->advertised |= ADVERTISED_10000baseT_Full;
  767. a = sw_r32(RTL930X_MAC_EEE_ABLTY);
  768. a = sw_r32(RTL930X_MAC_EEE_ABLTY);
  769. pr_info("Link partner: %08x\n", a);
  770. if (a & BIT(port)) {
  771. e->lp_advertised = ADVERTISED_100baseT_Full;
  772. e->lp_advertised |= ADVERTISED_1000baseT_Full;
  773. if (priv->ports[port].is2G5)
  774. e->lp_advertised |= ADVERTISED_2500baseX_Full;
  775. if (priv->ports[port].is10G)
  776. e->lp_advertised |= ADVERTISED_10000baseT_Full;
  777. }
  778. // Read 2x to clear latched state
  779. a = sw_r32(RTL930X_EEEP_PORT_CTRL(port));
  780. a = sw_r32(RTL930X_EEEP_PORT_CTRL(port));
  781. pr_info("%s RTL930X_EEEP_PORT_CTRL: %08x\n", __func__, a);
  782. return 0;
  783. }
  784. static void rtl930x_init_eee(struct rtl838x_switch_priv *priv, bool enable)
  785. {
  786. int i;
  787. pr_info("Setting up EEE, state: %d\n", enable);
  788. // Setup EEE on all ports
  789. for (i = 0; i < priv->cpu_port; i++) {
  790. if (priv->ports[i].phy)
  791. rtl930x_port_eee_set(priv, i, enable);
  792. }
  793. priv->eee_enabled = enable;
  794. }
  795. const struct rtl838x_reg rtl930x_reg = {
  796. .mask_port_reg_be = rtl838x_mask_port_reg,
  797. .set_port_reg_be = rtl838x_set_port_reg,
  798. .get_port_reg_be = rtl838x_get_port_reg,
  799. .mask_port_reg_le = rtl838x_mask_port_reg,
  800. .set_port_reg_le = rtl838x_set_port_reg,
  801. .get_port_reg_le = rtl838x_get_port_reg,
  802. .stat_port_rst = RTL930X_STAT_PORT_RST,
  803. .stat_rst = RTL930X_STAT_RST,
  804. .stat_port_std_mib = RTL930X_STAT_PORT_MIB_CNTR,
  805. .traffic_enable = rtl930x_traffic_enable,
  806. .traffic_disable = rtl930x_traffic_disable,
  807. .traffic_get = rtl930x_traffic_get,
  808. .traffic_set = rtl930x_traffic_set,
  809. .l2_ctrl_0 = RTL930X_L2_CTRL,
  810. .l2_ctrl_1 = RTL930X_L2_AGE_CTRL,
  811. .l2_port_aging_out = RTL930X_L2_PORT_AGE_CTRL,
  812. .smi_poll_ctrl = RTL930X_SMI_POLL_CTRL, // TODO: Difference to RTL9300_SMI_PRVTE_POLLING_CTRL
  813. .l2_tbl_flush_ctrl = RTL930X_L2_TBL_FLUSH_CTRL,
  814. .exec_tbl0_cmd = rtl930x_exec_tbl0_cmd,
  815. .exec_tbl1_cmd = rtl930x_exec_tbl1_cmd,
  816. .tbl_access_data_0 = rtl930x_tbl_access_data_0,
  817. .isr_glb_src = RTL930X_ISR_GLB,
  818. .isr_port_link_sts_chg = RTL930X_ISR_PORT_LINK_STS_CHG,
  819. .imr_port_link_sts_chg = RTL930X_IMR_PORT_LINK_STS_CHG,
  820. .imr_glb = RTL930X_IMR_GLB,
  821. .vlan_tables_read = rtl930x_vlan_tables_read,
  822. .vlan_set_tagged = rtl930x_vlan_set_tagged,
  823. .vlan_set_untagged = rtl930x_vlan_set_untagged,
  824. .vlan_profile_dump = rtl930x_vlan_profile_dump,
  825. .vlan_profile_setup = rtl930x_vlan_profile_setup,
  826. .vlan_fwd_on_inner = rtl930x_vlan_fwd_on_inner,
  827. .stp_get = rtl930x_stp_get,
  828. .stp_set = rtl930x_stp_set,
  829. .mac_force_mode_ctrl = rtl930x_mac_force_mode_ctrl,
  830. .mac_port_ctrl = rtl930x_mac_port_ctrl,
  831. .l2_port_new_salrn = rtl930x_l2_port_new_salrn,
  832. .l2_port_new_sa_fwd = rtl930x_l2_port_new_sa_fwd,
  833. .mir_ctrl = RTL930X_MIR_CTRL,
  834. .mir_dpm = RTL930X_MIR_DPM_CTRL,
  835. .mir_spm = RTL930X_MIR_SPM_CTRL,
  836. .mac_link_sts = RTL930X_MAC_LINK_STS,
  837. .mac_link_dup_sts = RTL930X_MAC_LINK_DUP_STS,
  838. .mac_link_spd_sts = rtl930x_mac_link_spd_sts,
  839. .mac_rx_pause_sts = RTL930X_MAC_RX_PAUSE_STS,
  840. .mac_tx_pause_sts = RTL930X_MAC_TX_PAUSE_STS,
  841. .read_l2_entry_using_hash = rtl930x_read_l2_entry_using_hash,
  842. .write_l2_entry_using_hash = rtl930x_write_l2_entry_using_hash,
  843. .read_cam = rtl930x_read_cam,
  844. .write_cam = rtl930x_write_cam,
  845. .vlan_port_egr_filter = RTL930X_VLAN_PORT_EGR_FLTR,
  846. .vlan_port_igr_filter = RTL930X_VLAN_PORT_IGR_FLTR(0),
  847. .vlan_port_pb = RTL930X_VLAN_PORT_PB_VLAN,
  848. .vlan_port_tag_sts_ctrl = RTL930X_VLAN_PORT_TAG_STS_CTRL,
  849. .trk_mbr_ctr = rtl930x_trk_mbr_ctr,
  850. .rma_bpdu_fld_pmask = RTL930X_RMA_BPDU_FLD_PMSK,
  851. .init_eee = rtl930x_init_eee,
  852. .port_eee_set = rtl930x_port_eee_set,
  853. .eee_port_ability = rtl930x_eee_port_ability,
  854. .read_mcast_pmask = rtl930x_read_mcast_pmask,
  855. .write_mcast_pmask = rtl930x_write_mcast_pmask,
  856. };