spectrum_fid.c 28 KB

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