spectrum_fid.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
  3. #include <linux/kernel.h>
  4. #include <linux/bitops.h>
  5. #include <linux/if_vlan.h>
  6. #include <linux/if_bridge.h>
  7. #include <linux/netdevice.h>
  8. #include <linux/rtnetlink.h>
  9. #include "spectrum.h"
  10. #include "reg.h"
  11. struct mlxsw_sp_fid_family;
  12. struct mlxsw_sp_fid_core {
  13. struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
  14. unsigned int *port_fid_mappings;
  15. };
  16. struct mlxsw_sp_fid {
  17. struct list_head list;
  18. struct mlxsw_sp_rif *rif;
  19. unsigned int ref_count;
  20. u16 fid_index;
  21. struct mlxsw_sp_fid_family *fid_family;
  22. };
  23. struct mlxsw_sp_fid_8021q {
  24. struct mlxsw_sp_fid common;
  25. u16 vid;
  26. };
  27. struct mlxsw_sp_fid_8021d {
  28. struct mlxsw_sp_fid common;
  29. int br_ifindex;
  30. };
  31. struct mlxsw_sp_flood_table {
  32. enum mlxsw_sp_flood_type packet_type;
  33. enum mlxsw_reg_sfgc_bridge_type bridge_type;
  34. enum mlxsw_flood_table_type table_type;
  35. int table_index;
  36. };
  37. struct mlxsw_sp_fid_ops {
  38. void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
  39. int (*configure)(struct mlxsw_sp_fid *fid);
  40. void (*deconfigure)(struct mlxsw_sp_fid *fid);
  41. int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
  42. u16 *p_fid_index);
  43. bool (*compare)(const struct mlxsw_sp_fid *fid,
  44. const void *arg);
  45. u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
  46. int (*port_vid_map)(struct mlxsw_sp_fid *fid,
  47. struct mlxsw_sp_port *port, u16 vid);
  48. void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
  49. struct mlxsw_sp_port *port, u16 vid);
  50. };
  51. struct mlxsw_sp_fid_family {
  52. enum mlxsw_sp_fid_type type;
  53. size_t fid_size;
  54. u16 start_index;
  55. u16 end_index;
  56. struct list_head fids_list;
  57. unsigned long *fids_bitmap;
  58. const struct mlxsw_sp_flood_table *flood_tables;
  59. int nr_flood_tables;
  60. enum mlxsw_sp_rif_type rif_type;
  61. const struct mlxsw_sp_fid_ops *ops;
  62. struct mlxsw_sp *mlxsw_sp;
  63. };
  64. static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
  65. [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
  66. };
  67. static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
  68. [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
  69. [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
  70. [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
  71. [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
  72. [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
  73. };
  74. static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
  75. [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
  76. };
  77. static const int *mlxsw_sp_packet_type_sfgc_types[] = {
  78. [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
  79. [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
  80. [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
  81. };
  82. static const struct mlxsw_sp_flood_table *
  83. mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
  84. enum mlxsw_sp_flood_type packet_type)
  85. {
  86. struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
  87. int i;
  88. for (i = 0; i < fid_family->nr_flood_tables; i++) {
  89. if (fid_family->flood_tables[i].packet_type != packet_type)
  90. continue;
  91. return &fid_family->flood_tables[i];
  92. }
  93. return NULL;
  94. }
  95. int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
  96. enum mlxsw_sp_flood_type packet_type, u8 local_port,
  97. bool member)
  98. {
  99. struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
  100. const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
  101. const struct mlxsw_sp_flood_table *flood_table;
  102. char *sftr_pl;
  103. int err;
  104. if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
  105. return -EINVAL;
  106. flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
  107. if (!flood_table)
  108. return -ESRCH;
  109. sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
  110. if (!sftr_pl)
  111. return -ENOMEM;
  112. mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index,
  113. ops->flood_index(fid), flood_table->table_type, 1,
  114. local_port, member);
  115. err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr),
  116. sftr_pl);
  117. kfree(sftr_pl);
  118. return err;
  119. }
  120. int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
  121. struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
  122. {
  123. if (WARN_ON(!fid->fid_family->ops->port_vid_map))
  124. return -EINVAL;
  125. return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
  126. }
  127. void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
  128. struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
  129. {
  130. fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
  131. }
  132. enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid)
  133. {
  134. return fid->fid_family->rif_type;
  135. }
  136. u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
  137. {
  138. return fid->fid_index;
  139. }
  140. enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
  141. {
  142. return fid->fid_family->type;
  143. }
  144. void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
  145. {
  146. fid->rif = rif;
  147. }
  148. enum mlxsw_sp_rif_type
  149. mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
  150. enum mlxsw_sp_fid_type type)
  151. {
  152. struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
  153. return fid_core->fid_family_arr[type]->rif_type;
  154. }
  155. static struct mlxsw_sp_fid_8021q *
  156. mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
  157. {
  158. return container_of(fid, struct mlxsw_sp_fid_8021q, common);
  159. }
  160. u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
  161. {
  162. return mlxsw_sp_fid_8021q_fid(fid)->vid;
  163. }
  164. static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
  165. {
  166. u16 vid = *(u16 *) arg;
  167. mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
  168. }
  169. static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
  170. {
  171. return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
  172. MLXSW_REG_SFMR_OP_DESTROY_FID;
  173. }
  174. static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
  175. u16 fid_offset, bool valid)
  176. {
  177. char sfmr_pl[MLXSW_REG_SFMR_LEN];
  178. mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
  179. fid_offset);
  180. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
  181. }
  182. static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
  183. u16 vid, bool valid)
  184. {
  185. enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
  186. char svfa_pl[MLXSW_REG_SVFA_LEN];
  187. mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid);
  188. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
  189. }
  190. static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
  191. u8 local_port, u16 vid, bool valid)
  192. {
  193. enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
  194. char svfa_pl[MLXSW_REG_SVFA_LEN];
  195. mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
  196. return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
  197. }
  198. static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
  199. {
  200. struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
  201. struct mlxsw_sp_fid_8021q *fid_8021q;
  202. int err;
  203. err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true);
  204. if (err)
  205. return err;
  206. fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
  207. err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid,
  208. true);
  209. if (err)
  210. goto err_fid_map;
  211. return 0;
  212. err_fid_map:
  213. mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
  214. return err;
  215. }
  216. static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
  217. {
  218. struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
  219. struct mlxsw_sp_fid_8021q *fid_8021q;
  220. fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
  221. mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false);
  222. mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
  223. }
  224. static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid,
  225. const void *arg, u16 *p_fid_index)
  226. {
  227. struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
  228. u16 vid = *(u16 *) arg;
  229. /* Use 1:1 mapping for simplicity although not a must */
  230. if (vid < fid_family->start_index || vid > fid_family->end_index)
  231. return -EINVAL;
  232. *p_fid_index = vid;
  233. return 0;
  234. }
  235. static bool
  236. mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
  237. {
  238. u16 vid = *(u16 *) arg;
  239. return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
  240. }
  241. static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
  242. {
  243. return fid->fid_index;
  244. }
  245. static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
  246. struct mlxsw_sp_port *mlxsw_sp_port,
  247. u16 vid)
  248. {
  249. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  250. u8 local_port = mlxsw_sp_port->local_port;
  251. /* In case there are no {Port, VID} => FID mappings on the port,
  252. * we can use the global VID => FID mapping we created when the
  253. * FID was configured.
  254. */
  255. if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
  256. return 0;
  257. return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port,
  258. vid, true);
  259. }
  260. static void
  261. mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
  262. struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
  263. {
  264. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  265. u8 local_port = mlxsw_sp_port->local_port;
  266. if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
  267. return;
  268. __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid,
  269. false);
  270. }
  271. static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
  272. .setup = mlxsw_sp_fid_8021q_setup,
  273. .configure = mlxsw_sp_fid_8021q_configure,
  274. .deconfigure = mlxsw_sp_fid_8021q_deconfigure,
  275. .index_alloc = mlxsw_sp_fid_8021q_index_alloc,
  276. .compare = mlxsw_sp_fid_8021q_compare,
  277. .flood_index = mlxsw_sp_fid_8021q_flood_index,
  278. .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
  279. .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
  280. };
  281. static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = {
  282. {
  283. .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
  284. .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
  285. .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
  286. .table_index = 0,
  287. },
  288. {
  289. .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
  290. .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
  291. .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
  292. .table_index = 1,
  293. },
  294. {
  295. .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
  296. .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
  297. .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
  298. .table_index = 2,
  299. },
  300. };
  301. /* Range and flood configuration must match mlxsw_config_profile */
  302. static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = {
  303. .type = MLXSW_SP_FID_TYPE_8021Q,
  304. .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
  305. .start_index = 1,
  306. .end_index = VLAN_VID_MASK,
  307. .flood_tables = mlxsw_sp_fid_8021q_flood_tables,
  308. .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables),
  309. .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
  310. .ops = &mlxsw_sp_fid_8021q_ops,
  311. };
  312. static struct mlxsw_sp_fid_8021d *
  313. mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
  314. {
  315. return container_of(fid, struct mlxsw_sp_fid_8021d, common);
  316. }
  317. static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
  318. {
  319. int br_ifindex = *(int *) arg;
  320. mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
  321. }
  322. static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
  323. {
  324. struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
  325. return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
  326. }
  327. static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
  328. {
  329. mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
  330. }
  331. static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
  332. const void *arg, u16 *p_fid_index)
  333. {
  334. struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
  335. u16 nr_fids, fid_index;
  336. nr_fids = fid_family->end_index - fid_family->start_index + 1;
  337. fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
  338. if (fid_index == nr_fids)
  339. return -ENOBUFS;
  340. *p_fid_index = fid_family->start_index + fid_index;
  341. return 0;
  342. }
  343. static bool
  344. mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
  345. {
  346. int br_ifindex = *(int *) arg;
  347. return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
  348. }
  349. static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
  350. {
  351. return fid->fid_index - fid->fid_family->start_index;
  352. }
  353. static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
  354. {
  355. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  356. struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
  357. int err;
  358. list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
  359. list) {
  360. struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
  361. u16 vid = mlxsw_sp_port_vlan->vid;
  362. if (!fid)
  363. continue;
  364. err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
  365. mlxsw_sp_port->local_port,
  366. vid, true);
  367. if (err)
  368. goto err_fid_port_vid_map;
  369. }
  370. err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
  371. if (err)
  372. goto err_port_vp_mode_set;
  373. return 0;
  374. err_port_vp_mode_set:
  375. err_fid_port_vid_map:
  376. list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
  377. &mlxsw_sp_port->vlans_list, list) {
  378. struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
  379. u16 vid = mlxsw_sp_port_vlan->vid;
  380. if (!fid)
  381. continue;
  382. __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
  383. mlxsw_sp_port->local_port, vid,
  384. false);
  385. }
  386. return err;
  387. }
  388. static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
  389. {
  390. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  391. struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
  392. mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
  393. list_for_each_entry_reverse(mlxsw_sp_port_vlan,
  394. &mlxsw_sp_port->vlans_list, list) {
  395. struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
  396. u16 vid = mlxsw_sp_port_vlan->vid;
  397. if (!fid)
  398. continue;
  399. __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
  400. mlxsw_sp_port->local_port, vid,
  401. false);
  402. }
  403. }
  404. static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
  405. struct mlxsw_sp_port *mlxsw_sp_port,
  406. u16 vid)
  407. {
  408. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  409. u8 local_port = mlxsw_sp_port->local_port;
  410. int err;
  411. err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
  412. mlxsw_sp_port->local_port, vid, true);
  413. if (err)
  414. return err;
  415. if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
  416. err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
  417. if (err)
  418. goto err_port_vp_mode_trans;
  419. }
  420. return 0;
  421. err_port_vp_mode_trans:
  422. mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
  423. __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
  424. mlxsw_sp_port->local_port, vid, false);
  425. return err;
  426. }
  427. static void
  428. mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
  429. struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
  430. {
  431. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  432. u8 local_port = mlxsw_sp_port->local_port;
  433. if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
  434. mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
  435. mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
  436. __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
  437. mlxsw_sp_port->local_port, vid, false);
  438. }
  439. static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
  440. .setup = mlxsw_sp_fid_8021d_setup,
  441. .configure = mlxsw_sp_fid_8021d_configure,
  442. .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
  443. .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
  444. .compare = mlxsw_sp_fid_8021d_compare,
  445. .flood_index = mlxsw_sp_fid_8021d_flood_index,
  446. .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
  447. .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
  448. };
  449. static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
  450. {
  451. .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
  452. .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
  453. .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
  454. .table_index = 0,
  455. },
  456. {
  457. .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
  458. .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
  459. .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
  460. .table_index = 1,
  461. },
  462. {
  463. .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
  464. .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
  465. .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
  466. .table_index = 2,
  467. },
  468. };
  469. /* Range and flood configuration must match mlxsw_config_profile */
  470. static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
  471. .type = MLXSW_SP_FID_TYPE_8021D,
  472. .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
  473. .start_index = VLAN_N_VID,
  474. .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
  475. .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
  476. .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
  477. .rif_type = MLXSW_SP_RIF_TYPE_FID,
  478. .ops = &mlxsw_sp_fid_8021d_ops,
  479. };
  480. static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
  481. {
  482. /* rFIDs are allocated by the device during init */
  483. return 0;
  484. }
  485. static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
  486. {
  487. }
  488. static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
  489. const void *arg, u16 *p_fid_index)
  490. {
  491. u16 rif_index = *(u16 *) arg;
  492. *p_fid_index = fid->fid_family->start_index + rif_index;
  493. return 0;
  494. }
  495. static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
  496. const void *arg)
  497. {
  498. u16 rif_index = *(u16 *) arg;
  499. return fid->fid_index == rif_index + fid->fid_family->start_index;
  500. }
  501. static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
  502. struct mlxsw_sp_port *mlxsw_sp_port,
  503. u16 vid)
  504. {
  505. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  506. u8 local_port = mlxsw_sp_port->local_port;
  507. int err;
  508. /* We only need to transition the port to virtual mode since
  509. * {Port, VID} => FID is done by the firmware upon RIF creation.
  510. */
  511. if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
  512. err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
  513. if (err)
  514. goto err_port_vp_mode_trans;
  515. }
  516. return 0;
  517. err_port_vp_mode_trans:
  518. mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
  519. return err;
  520. }
  521. static void
  522. mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
  523. struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
  524. {
  525. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  526. u8 local_port = mlxsw_sp_port->local_port;
  527. if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
  528. mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
  529. mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
  530. }
  531. static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
  532. .configure = mlxsw_sp_fid_rfid_configure,
  533. .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
  534. .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
  535. .compare = mlxsw_sp_fid_rfid_compare,
  536. .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
  537. .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
  538. };
  539. #define MLXSW_SP_RFID_BASE (15 * 1024)
  540. #define MLXSW_SP_RFID_MAX 1024
  541. static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
  542. .type = MLXSW_SP_FID_TYPE_RFID,
  543. .fid_size = sizeof(struct mlxsw_sp_fid),
  544. .start_index = MLXSW_SP_RFID_BASE,
  545. .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
  546. .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
  547. .ops = &mlxsw_sp_fid_rfid_ops,
  548. };
  549. static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
  550. {
  551. struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
  552. return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
  553. }
  554. static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
  555. {
  556. mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
  557. }
  558. static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
  559. const void *arg, u16 *p_fid_index)
  560. {
  561. *p_fid_index = fid->fid_family->start_index;
  562. return 0;
  563. }
  564. static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
  565. const void *arg)
  566. {
  567. return true;
  568. }
  569. static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
  570. .configure = mlxsw_sp_fid_dummy_configure,
  571. .deconfigure = mlxsw_sp_fid_dummy_deconfigure,
  572. .index_alloc = mlxsw_sp_fid_dummy_index_alloc,
  573. .compare = mlxsw_sp_fid_dummy_compare,
  574. };
  575. static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
  576. .type = MLXSW_SP_FID_TYPE_DUMMY,
  577. .fid_size = sizeof(struct mlxsw_sp_fid),
  578. .start_index = VLAN_N_VID - 1,
  579. .end_index = VLAN_N_VID - 1,
  580. .ops = &mlxsw_sp_fid_dummy_ops,
  581. };
  582. static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
  583. [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family,
  584. [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family,
  585. [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
  586. [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family,
  587. };
  588. static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
  589. enum mlxsw_sp_fid_type type,
  590. const void *arg)
  591. {
  592. struct mlxsw_sp_fid_family *fid_family;
  593. struct mlxsw_sp_fid *fid;
  594. u16 fid_index;
  595. int err;
  596. fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
  597. list_for_each_entry(fid, &fid_family->fids_list, list) {
  598. if (!fid->fid_family->ops->compare(fid, arg))
  599. continue;
  600. fid->ref_count++;
  601. return fid;
  602. }
  603. fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
  604. if (!fid)
  605. return ERR_PTR(-ENOMEM);
  606. fid->fid_family = fid_family;
  607. err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
  608. if (err)
  609. goto err_index_alloc;
  610. fid->fid_index = fid_index;
  611. __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
  612. if (fid->fid_family->ops->setup)
  613. fid->fid_family->ops->setup(fid, arg);
  614. err = fid->fid_family->ops->configure(fid);
  615. if (err)
  616. goto err_configure;
  617. list_add(&fid->list, &fid_family->fids_list);
  618. fid->ref_count++;
  619. return fid;
  620. err_configure:
  621. __clear_bit(fid_index - fid_family->start_index,
  622. fid_family->fids_bitmap);
  623. err_index_alloc:
  624. kfree(fid);
  625. return ERR_PTR(err);
  626. }
  627. void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
  628. {
  629. struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
  630. if (--fid->ref_count == 1 && fid->rif) {
  631. /* Destroy the associated RIF and let it drop the last
  632. * reference on the FID.
  633. */
  634. return mlxsw_sp_rif_destroy(fid->rif);
  635. } else if (fid->ref_count == 0) {
  636. list_del(&fid->list);
  637. fid->fid_family->ops->deconfigure(fid);
  638. __clear_bit(fid->fid_index - fid_family->start_index,
  639. fid_family->fids_bitmap);
  640. kfree(fid);
  641. }
  642. }
  643. struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
  644. {
  645. return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
  646. }
  647. struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
  648. int br_ifindex)
  649. {
  650. return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
  651. }
  652. struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
  653. u16 rif_index)
  654. {
  655. return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
  656. }
  657. struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
  658. {
  659. return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
  660. }
  661. static int
  662. mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
  663. const struct mlxsw_sp_flood_table *flood_table)
  664. {
  665. enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
  666. const int *sfgc_packet_types;
  667. int i;
  668. sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
  669. for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
  670. struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
  671. char sfgc_pl[MLXSW_REG_SFGC_LEN];
  672. int err;
  673. if (!sfgc_packet_types[i])
  674. continue;
  675. mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
  676. flood_table->table_type,
  677. flood_table->table_index);
  678. err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
  679. if (err)
  680. return err;
  681. }
  682. return 0;
  683. }
  684. static int
  685. mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
  686. {
  687. int i;
  688. for (i = 0; i < fid_family->nr_flood_tables; i++) {
  689. const struct mlxsw_sp_flood_table *flood_table;
  690. int err;
  691. flood_table = &fid_family->flood_tables[i];
  692. err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
  693. if (err)
  694. return err;
  695. }
  696. return 0;
  697. }
  698. static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
  699. const struct mlxsw_sp_fid_family *tmpl)
  700. {
  701. u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
  702. struct mlxsw_sp_fid_family *fid_family;
  703. int err;
  704. fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
  705. if (!fid_family)
  706. return -ENOMEM;
  707. fid_family->mlxsw_sp = mlxsw_sp;
  708. INIT_LIST_HEAD(&fid_family->fids_list);
  709. fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids),
  710. sizeof(unsigned long), GFP_KERNEL);
  711. if (!fid_family->fids_bitmap) {
  712. err = -ENOMEM;
  713. goto err_alloc_fids_bitmap;
  714. }
  715. if (fid_family->flood_tables) {
  716. err = mlxsw_sp_fid_flood_tables_init(fid_family);
  717. if (err)
  718. goto err_fid_flood_tables_init;
  719. }
  720. mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
  721. return 0;
  722. err_fid_flood_tables_init:
  723. kfree(fid_family->fids_bitmap);
  724. err_alloc_fids_bitmap:
  725. kfree(fid_family);
  726. return err;
  727. }
  728. static void
  729. mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
  730. struct mlxsw_sp_fid_family *fid_family)
  731. {
  732. mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
  733. kfree(fid_family->fids_bitmap);
  734. WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
  735. kfree(fid_family);
  736. }
  737. int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
  738. {
  739. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  740. /* Track number of FIDs configured on the port with mapping type
  741. * PORT_VID_TO_FID, so that we know when to transition the port
  742. * back to non-virtual (VLAN) mode.
  743. */
  744. mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
  745. return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
  746. }
  747. void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
  748. {
  749. struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  750. mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
  751. }
  752. int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
  753. {
  754. unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
  755. struct mlxsw_sp_fid_core *fid_core;
  756. int err, i;
  757. fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
  758. if (!fid_core)
  759. return -ENOMEM;
  760. mlxsw_sp->fid_core = fid_core;
  761. fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
  762. GFP_KERNEL);
  763. if (!fid_core->port_fid_mappings) {
  764. err = -ENOMEM;
  765. goto err_alloc_port_fid_mappings;
  766. }
  767. for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
  768. err = mlxsw_sp_fid_family_register(mlxsw_sp,
  769. mlxsw_sp_fid_family_arr[i]);
  770. if (err)
  771. goto err_fid_ops_register;
  772. }
  773. return 0;
  774. err_fid_ops_register:
  775. for (i--; i >= 0; i--) {
  776. struct mlxsw_sp_fid_family *fid_family;
  777. fid_family = fid_core->fid_family_arr[i];
  778. mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
  779. }
  780. kfree(fid_core->port_fid_mappings);
  781. err_alloc_port_fid_mappings:
  782. kfree(fid_core);
  783. return err;
  784. }
  785. void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
  786. {
  787. struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
  788. int i;
  789. for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
  790. mlxsw_sp_fid_family_unregister(mlxsw_sp,
  791. fid_core->fid_family_arr[i]);
  792. kfree(fid_core->port_fid_mappings);
  793. kfree(fid_core);
  794. }