devlink.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <net/dsa.h>
  3. #include "chip.h"
  4. #include "devlink.h"
  5. #include "global1.h"
  6. #include "global2.h"
  7. #include "port.h"
  8. static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
  9. {
  10. if (chip->info->ops->atu_get_hash)
  11. return chip->info->ops->atu_get_hash(chip, hash);
  12. return -EOPNOTSUPP;
  13. }
  14. static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
  15. {
  16. if (chip->info->ops->atu_set_hash)
  17. return chip->info->ops->atu_set_hash(chip, hash);
  18. return -EOPNOTSUPP;
  19. }
  20. enum mv88e6xxx_devlink_param_id {
  21. MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
  22. MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
  23. };
  24. int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
  25. struct devlink_param_gset_ctx *ctx)
  26. {
  27. struct mv88e6xxx_chip *chip = ds->priv;
  28. int err;
  29. mv88e6xxx_reg_lock(chip);
  30. switch (id) {
  31. case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
  32. err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
  33. break;
  34. default:
  35. err = -EOPNOTSUPP;
  36. break;
  37. }
  38. mv88e6xxx_reg_unlock(chip);
  39. return err;
  40. }
  41. int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
  42. struct devlink_param_gset_ctx *ctx)
  43. {
  44. struct mv88e6xxx_chip *chip = ds->priv;
  45. int err;
  46. mv88e6xxx_reg_lock(chip);
  47. switch (id) {
  48. case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
  49. err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
  50. break;
  51. default:
  52. err = -EOPNOTSUPP;
  53. break;
  54. }
  55. mv88e6xxx_reg_unlock(chip);
  56. return err;
  57. }
  58. static const struct devlink_param mv88e6xxx_devlink_params[] = {
  59. DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
  60. "ATU_hash", DEVLINK_PARAM_TYPE_U8,
  61. BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
  62. };
  63. int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
  64. {
  65. return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
  66. ARRAY_SIZE(mv88e6xxx_devlink_params));
  67. }
  68. void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
  69. {
  70. dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
  71. ARRAY_SIZE(mv88e6xxx_devlink_params));
  72. }
  73. enum mv88e6xxx_devlink_resource_id {
  74. MV88E6XXX_RESOURCE_ID_ATU,
  75. MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
  76. MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
  77. MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
  78. MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
  79. };
  80. static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
  81. u16 bin)
  82. {
  83. u16 occupancy = 0;
  84. int err;
  85. mv88e6xxx_reg_lock(chip);
  86. err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
  87. bin);
  88. if (err) {
  89. dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
  90. goto unlock;
  91. }
  92. err = mv88e6xxx_g1_atu_get_next(chip, 0);
  93. if (err) {
  94. dev_err(chip->dev, "failed to perform ATU get next\n");
  95. goto unlock;
  96. }
  97. err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
  98. if (err) {
  99. dev_err(chip->dev, "failed to get ATU stats\n");
  100. goto unlock;
  101. }
  102. occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
  103. unlock:
  104. mv88e6xxx_reg_unlock(chip);
  105. return occupancy;
  106. }
  107. static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
  108. {
  109. struct mv88e6xxx_chip *chip = priv;
  110. return mv88e6xxx_devlink_atu_bin_get(chip,
  111. MV88E6XXX_G2_ATU_STATS_BIN_0);
  112. }
  113. static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
  114. {
  115. struct mv88e6xxx_chip *chip = priv;
  116. return mv88e6xxx_devlink_atu_bin_get(chip,
  117. MV88E6XXX_G2_ATU_STATS_BIN_1);
  118. }
  119. static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
  120. {
  121. struct mv88e6xxx_chip *chip = priv;
  122. return mv88e6xxx_devlink_atu_bin_get(chip,
  123. MV88E6XXX_G2_ATU_STATS_BIN_2);
  124. }
  125. static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
  126. {
  127. struct mv88e6xxx_chip *chip = priv;
  128. return mv88e6xxx_devlink_atu_bin_get(chip,
  129. MV88E6XXX_G2_ATU_STATS_BIN_3);
  130. }
  131. static u64 mv88e6xxx_devlink_atu_get(void *priv)
  132. {
  133. return mv88e6xxx_devlink_atu_bin_0_get(priv) +
  134. mv88e6xxx_devlink_atu_bin_1_get(priv) +
  135. mv88e6xxx_devlink_atu_bin_2_get(priv) +
  136. mv88e6xxx_devlink_atu_bin_3_get(priv);
  137. }
  138. int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
  139. {
  140. struct devlink_resource_size_params size_params;
  141. struct mv88e6xxx_chip *chip = ds->priv;
  142. int err;
  143. devlink_resource_size_params_init(&size_params,
  144. mv88e6xxx_num_macs(chip),
  145. mv88e6xxx_num_macs(chip),
  146. 1, DEVLINK_RESOURCE_UNIT_ENTRY);
  147. err = dsa_devlink_resource_register(ds, "ATU",
  148. mv88e6xxx_num_macs(chip),
  149. MV88E6XXX_RESOURCE_ID_ATU,
  150. DEVLINK_RESOURCE_ID_PARENT_TOP,
  151. &size_params);
  152. if (err)
  153. goto out;
  154. devlink_resource_size_params_init(&size_params,
  155. mv88e6xxx_num_macs(chip) / 4,
  156. mv88e6xxx_num_macs(chip) / 4,
  157. 1, DEVLINK_RESOURCE_UNIT_ENTRY);
  158. err = dsa_devlink_resource_register(ds, "ATU_bin_0",
  159. mv88e6xxx_num_macs(chip) / 4,
  160. MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
  161. MV88E6XXX_RESOURCE_ID_ATU,
  162. &size_params);
  163. if (err)
  164. goto out;
  165. err = dsa_devlink_resource_register(ds, "ATU_bin_1",
  166. mv88e6xxx_num_macs(chip) / 4,
  167. MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
  168. MV88E6XXX_RESOURCE_ID_ATU,
  169. &size_params);
  170. if (err)
  171. goto out;
  172. err = dsa_devlink_resource_register(ds, "ATU_bin_2",
  173. mv88e6xxx_num_macs(chip) / 4,
  174. MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
  175. MV88E6XXX_RESOURCE_ID_ATU,
  176. &size_params);
  177. if (err)
  178. goto out;
  179. err = dsa_devlink_resource_register(ds, "ATU_bin_3",
  180. mv88e6xxx_num_macs(chip) / 4,
  181. MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
  182. MV88E6XXX_RESOURCE_ID_ATU,
  183. &size_params);
  184. if (err)
  185. goto out;
  186. dsa_devlink_resource_occ_get_register(ds,
  187. MV88E6XXX_RESOURCE_ID_ATU,
  188. mv88e6xxx_devlink_atu_get,
  189. chip);
  190. dsa_devlink_resource_occ_get_register(ds,
  191. MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
  192. mv88e6xxx_devlink_atu_bin_0_get,
  193. chip);
  194. dsa_devlink_resource_occ_get_register(ds,
  195. MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
  196. mv88e6xxx_devlink_atu_bin_1_get,
  197. chip);
  198. dsa_devlink_resource_occ_get_register(ds,
  199. MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
  200. mv88e6xxx_devlink_atu_bin_2_get,
  201. chip);
  202. dsa_devlink_resource_occ_get_register(ds,
  203. MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
  204. mv88e6xxx_devlink_atu_bin_3_get,
  205. chip);
  206. return 0;
  207. out:
  208. dsa_devlink_resources_unregister(ds);
  209. return err;
  210. }
  211. static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
  212. const struct devlink_region_ops *ops,
  213. struct netlink_ext_ack *extack,
  214. u8 **data)
  215. {
  216. struct mv88e6xxx_region_priv *region_priv = ops->priv;
  217. struct dsa_switch *ds = dsa_devlink_to_ds(dl);
  218. struct mv88e6xxx_chip *chip = ds->priv;
  219. u16 *registers;
  220. int i, err;
  221. registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
  222. if (!registers)
  223. return -ENOMEM;
  224. mv88e6xxx_reg_lock(chip);
  225. for (i = 0; i < 32; i++) {
  226. switch (region_priv->id) {
  227. case MV88E6XXX_REGION_GLOBAL1:
  228. err = mv88e6xxx_g1_read(chip, i, &registers[i]);
  229. break;
  230. case MV88E6XXX_REGION_GLOBAL2:
  231. err = mv88e6xxx_g2_read(chip, i, &registers[i]);
  232. break;
  233. default:
  234. err = -EOPNOTSUPP;
  235. }
  236. if (err) {
  237. kfree(registers);
  238. goto out;
  239. }
  240. }
  241. *data = (u8 *)registers;
  242. out:
  243. mv88e6xxx_reg_unlock(chip);
  244. return err;
  245. }
  246. /* The ATU entry varies between mv88e6xxx chipset generations. Define
  247. * a generic format which covers all the current and hopefully future
  248. * mv88e6xxx generations
  249. */
  250. struct mv88e6xxx_devlink_atu_entry {
  251. /* The FID is scattered over multiple registers. */
  252. u16 fid;
  253. u16 atu_op;
  254. u16 atu_data;
  255. u16 atu_01;
  256. u16 atu_23;
  257. u16 atu_45;
  258. };
  259. static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
  260. int fid,
  261. struct mv88e6xxx_devlink_atu_entry *table,
  262. int *count)
  263. {
  264. u16 atu_op, atu_data, atu_01, atu_23, atu_45;
  265. struct mv88e6xxx_atu_entry addr;
  266. int err;
  267. addr.state = 0;
  268. eth_broadcast_addr(addr.mac);
  269. do {
  270. err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
  271. if (err)
  272. return err;
  273. if (!addr.state)
  274. break;
  275. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
  276. if (err)
  277. return err;
  278. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
  279. if (err)
  280. return err;
  281. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
  282. if (err)
  283. return err;
  284. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
  285. if (err)
  286. return err;
  287. err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
  288. if (err)
  289. return err;
  290. table[*count].fid = fid;
  291. table[*count].atu_op = atu_op;
  292. table[*count].atu_data = atu_data;
  293. table[*count].atu_01 = atu_01;
  294. table[*count].atu_23 = atu_23;
  295. table[*count].atu_45 = atu_45;
  296. (*count)++;
  297. } while (!is_broadcast_ether_addr(addr.mac));
  298. return 0;
  299. }
  300. static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
  301. const struct devlink_region_ops *ops,
  302. struct netlink_ext_ack *extack,
  303. u8 **data)
  304. {
  305. struct dsa_switch *ds = dsa_devlink_to_ds(dl);
  306. DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
  307. struct mv88e6xxx_devlink_atu_entry *table;
  308. struct mv88e6xxx_chip *chip = ds->priv;
  309. int fid = -1, count, err;
  310. table = kmalloc_array(mv88e6xxx_num_databases(chip),
  311. sizeof(struct mv88e6xxx_devlink_atu_entry),
  312. GFP_KERNEL);
  313. if (!table)
  314. return -ENOMEM;
  315. memset(table, 0, mv88e6xxx_num_databases(chip) *
  316. sizeof(struct mv88e6xxx_devlink_atu_entry));
  317. count = 0;
  318. mv88e6xxx_reg_lock(chip);
  319. err = mv88e6xxx_fid_map(chip, fid_bitmap);
  320. if (err) {
  321. kfree(table);
  322. goto out;
  323. }
  324. while (1) {
  325. fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);
  326. if (fid == MV88E6XXX_N_FID)
  327. break;
  328. err = mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
  329. &count);
  330. if (err) {
  331. kfree(table);
  332. goto out;
  333. }
  334. }
  335. *data = (u8 *)table;
  336. out:
  337. mv88e6xxx_reg_unlock(chip);
  338. return err;
  339. }
  340. /**
  341. * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
  342. * @fid: Global1/2: FID and VLAN policy.
  343. * @sid: Global1/3: SID, unknown filters and learning.
  344. * @op: Global1/5: FID (old chipsets).
  345. * @vid: Global1/6: VID, valid, and page.
  346. * @data: Global1/7-9: Membership data and priority override.
  347. * @resvd: Reserved. Also happens to align the size to 16B.
  348. *
  349. * The VTU entry format varies between chipset generations, the
  350. * descriptions above represent the superset of all possible
  351. * information, not all fields are valid on all devices. Since this is
  352. * a low-level debug interface, copy all data verbatim and defer
  353. * parsing to the consumer.
  354. */
  355. struct mv88e6xxx_devlink_vtu_entry {
  356. u16 fid;
  357. u16 sid;
  358. u16 op;
  359. u16 vid;
  360. u16 data[3];
  361. u16 resvd;
  362. };
  363. static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
  364. const struct devlink_region_ops *ops,
  365. struct netlink_ext_ack *extack,
  366. u8 **data)
  367. {
  368. struct mv88e6xxx_devlink_vtu_entry *table, *entry;
  369. struct dsa_switch *ds = dsa_devlink_to_ds(dl);
  370. struct mv88e6xxx_chip *chip = ds->priv;
  371. struct mv88e6xxx_vtu_entry vlan;
  372. int err;
  373. table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
  374. sizeof(struct mv88e6xxx_devlink_vtu_entry),
  375. GFP_KERNEL);
  376. if (!table)
  377. return -ENOMEM;
  378. entry = table;
  379. vlan.vid = mv88e6xxx_max_vid(chip);
  380. vlan.valid = false;
  381. mv88e6xxx_reg_lock(chip);
  382. do {
  383. err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
  384. if (err)
  385. break;
  386. if (!vlan.valid)
  387. break;
  388. err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
  389. &entry->fid);
  390. err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
  391. &entry->sid);
  392. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
  393. &entry->op);
  394. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
  395. &entry->vid);
  396. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
  397. &entry->data[0]);
  398. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
  399. &entry->data[1]);
  400. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
  401. &entry->data[2]);
  402. if (err)
  403. break;
  404. entry++;
  405. } while (vlan.vid < mv88e6xxx_max_vid(chip));
  406. mv88e6xxx_reg_unlock(chip);
  407. if (err) {
  408. kfree(table);
  409. return err;
  410. }
  411. *data = (u8 *)table;
  412. return 0;
  413. }
  414. /**
  415. * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
  416. * @sid: Global1/3: SID, unknown filters and learning.
  417. * @vid: Global1/6: Valid bit.
  418. * @data: Global1/7-9: Membership data and priority override.
  419. * @resvd: Reserved. In case we forgot something.
  420. *
  421. * The STU entry format varies between chipset generations. Peridot
  422. * and Amethyst packs the STU data into Global1/7-8. Older silicon
  423. * spreads the information across all three VTU data registers -
  424. * inheriting the layout of even older hardware that had no STU at
  425. * all. Since this is a low-level debug interface, copy all data
  426. * verbatim and defer parsing to the consumer.
  427. */
  428. struct mv88e6xxx_devlink_stu_entry {
  429. u16 sid;
  430. u16 vid;
  431. u16 data[3];
  432. u16 resvd;
  433. };
  434. static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
  435. const struct devlink_region_ops *ops,
  436. struct netlink_ext_ack *extack,
  437. u8 **data)
  438. {
  439. struct mv88e6xxx_devlink_stu_entry *table, *entry;
  440. struct dsa_switch *ds = dsa_devlink_to_ds(dl);
  441. struct mv88e6xxx_chip *chip = ds->priv;
  442. struct mv88e6xxx_stu_entry stu;
  443. int err;
  444. table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
  445. sizeof(struct mv88e6xxx_devlink_stu_entry),
  446. GFP_KERNEL);
  447. if (!table)
  448. return -ENOMEM;
  449. entry = table;
  450. stu.sid = mv88e6xxx_max_sid(chip);
  451. stu.valid = false;
  452. mv88e6xxx_reg_lock(chip);
  453. do {
  454. err = mv88e6xxx_g1_stu_getnext(chip, &stu);
  455. if (err)
  456. break;
  457. if (!stu.valid)
  458. break;
  459. err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
  460. &entry->sid);
  461. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
  462. &entry->vid);
  463. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
  464. &entry->data[0]);
  465. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
  466. &entry->data[1]);
  467. err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
  468. &entry->data[2]);
  469. if (err)
  470. break;
  471. entry++;
  472. } while (stu.sid < mv88e6xxx_max_sid(chip));
  473. mv88e6xxx_reg_unlock(chip);
  474. if (err) {
  475. kfree(table);
  476. return err;
  477. }
  478. *data = (u8 *)table;
  479. return 0;
  480. }
  481. static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
  482. const struct devlink_region_ops *ops,
  483. struct netlink_ext_ack *extack,
  484. u8 **data)
  485. {
  486. struct dsa_switch *ds = dsa_devlink_to_ds(dl);
  487. struct mv88e6xxx_chip *chip = ds->priv;
  488. int dev, port, err;
  489. u16 *pvt, *cur;
  490. pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
  491. if (!pvt)
  492. return -ENOMEM;
  493. mv88e6xxx_reg_lock(chip);
  494. cur = pvt;
  495. for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
  496. for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
  497. err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
  498. if (err)
  499. break;
  500. cur++;
  501. }
  502. }
  503. mv88e6xxx_reg_unlock(chip);
  504. if (err) {
  505. kfree(pvt);
  506. return err;
  507. }
  508. *data = (u8 *)pvt;
  509. return 0;
  510. }
  511. static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
  512. const struct devlink_port_region_ops *ops,
  513. struct netlink_ext_ack *extack,
  514. u8 **data)
  515. {
  516. struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
  517. int port = dsa_devlink_port_to_port(devlink_port);
  518. struct mv88e6xxx_chip *chip = ds->priv;
  519. u16 *registers;
  520. int i, err;
  521. registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
  522. if (!registers)
  523. return -ENOMEM;
  524. mv88e6xxx_reg_lock(chip);
  525. for (i = 0; i < 32; i++) {
  526. err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
  527. if (err) {
  528. kfree(registers);
  529. goto out;
  530. }
  531. }
  532. *data = (u8 *)registers;
  533. out:
  534. mv88e6xxx_reg_unlock(chip);
  535. return err;
  536. }
  537. static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
  538. .id = MV88E6XXX_REGION_GLOBAL1,
  539. };
  540. static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
  541. .name = "global1",
  542. .snapshot = mv88e6xxx_region_global_snapshot,
  543. .destructor = kfree,
  544. .priv = &mv88e6xxx_region_global1_priv,
  545. };
  546. static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
  547. .id = MV88E6XXX_REGION_GLOBAL2,
  548. };
  549. static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
  550. .name = "global2",
  551. .snapshot = mv88e6xxx_region_global_snapshot,
  552. .destructor = kfree,
  553. .priv = &mv88e6xxx_region_global2_priv,
  554. };
  555. static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
  556. .name = "atu",
  557. .snapshot = mv88e6xxx_region_atu_snapshot,
  558. .destructor = kfree,
  559. };
  560. static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
  561. .name = "vtu",
  562. .snapshot = mv88e6xxx_region_vtu_snapshot,
  563. .destructor = kfree,
  564. };
  565. static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
  566. .name = "stu",
  567. .snapshot = mv88e6xxx_region_stu_snapshot,
  568. .destructor = kfree,
  569. };
  570. static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
  571. .name = "pvt",
  572. .snapshot = mv88e6xxx_region_pvt_snapshot,
  573. .destructor = kfree,
  574. };
  575. static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
  576. .name = "port",
  577. .snapshot = mv88e6xxx_region_port_snapshot,
  578. .destructor = kfree,
  579. };
  580. struct mv88e6xxx_region {
  581. struct devlink_region_ops *ops;
  582. u64 size;
  583. bool (*cond)(struct mv88e6xxx_chip *chip);
  584. };
  585. static struct mv88e6xxx_region mv88e6xxx_regions[] = {
  586. [MV88E6XXX_REGION_GLOBAL1] = {
  587. .ops = &mv88e6xxx_region_global1_ops,
  588. .size = 32 * sizeof(u16)
  589. },
  590. [MV88E6XXX_REGION_GLOBAL2] = {
  591. .ops = &mv88e6xxx_region_global2_ops,
  592. .size = 32 * sizeof(u16) },
  593. [MV88E6XXX_REGION_ATU] = {
  594. .ops = &mv88e6xxx_region_atu_ops
  595. /* calculated at runtime */
  596. },
  597. [MV88E6XXX_REGION_VTU] = {
  598. .ops = &mv88e6xxx_region_vtu_ops
  599. /* calculated at runtime */
  600. },
  601. [MV88E6XXX_REGION_STU] = {
  602. .ops = &mv88e6xxx_region_stu_ops,
  603. .cond = mv88e6xxx_has_stu,
  604. /* calculated at runtime */
  605. },
  606. [MV88E6XXX_REGION_PVT] = {
  607. .ops = &mv88e6xxx_region_pvt_ops,
  608. .size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
  609. .cond = mv88e6xxx_has_pvt,
  610. },
  611. };
  612. void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
  613. {
  614. struct mv88e6xxx_chip *chip = ds->priv;
  615. int i;
  616. for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
  617. dsa_devlink_region_destroy(chip->regions[i]);
  618. }
  619. void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
  620. {
  621. struct mv88e6xxx_chip *chip = ds->priv;
  622. dsa_devlink_region_destroy(chip->ports[port].region);
  623. }
  624. int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
  625. {
  626. struct mv88e6xxx_chip *chip = ds->priv;
  627. struct devlink_region *region;
  628. region = dsa_devlink_port_region_create(ds,
  629. port,
  630. &mv88e6xxx_region_port_ops, 1,
  631. 32 * sizeof(u16));
  632. if (IS_ERR(region))
  633. return PTR_ERR(region);
  634. chip->ports[port].region = region;
  635. return 0;
  636. }
  637. int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
  638. {
  639. bool (*cond)(struct mv88e6xxx_chip *chip);
  640. struct mv88e6xxx_chip *chip = ds->priv;
  641. struct devlink_region_ops *ops;
  642. struct devlink_region *region;
  643. u64 size;
  644. int i, j;
  645. for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
  646. ops = mv88e6xxx_regions[i].ops;
  647. size = mv88e6xxx_regions[i].size;
  648. cond = mv88e6xxx_regions[i].cond;
  649. if (cond && !cond(chip))
  650. continue;
  651. switch (i) {
  652. case MV88E6XXX_REGION_ATU:
  653. size = mv88e6xxx_num_databases(chip) *
  654. sizeof(struct mv88e6xxx_devlink_atu_entry);
  655. break;
  656. case MV88E6XXX_REGION_VTU:
  657. size = (mv88e6xxx_max_vid(chip) + 1) *
  658. sizeof(struct mv88e6xxx_devlink_vtu_entry);
  659. break;
  660. case MV88E6XXX_REGION_STU:
  661. size = (mv88e6xxx_max_sid(chip) + 1) *
  662. sizeof(struct mv88e6xxx_devlink_stu_entry);
  663. break;
  664. }
  665. region = dsa_devlink_region_create(ds, ops, 1, size);
  666. if (IS_ERR(region))
  667. goto out;
  668. chip->regions[i] = region;
  669. }
  670. return 0;
  671. out:
  672. for (j = 0; j < i; j++)
  673. dsa_devlink_region_destroy(chip->regions[j]);
  674. return PTR_ERR(region);
  675. }
  676. int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
  677. struct devlink_info_req *req,
  678. struct netlink_ext_ack *extack)
  679. {
  680. struct mv88e6xxx_chip *chip = ds->priv;
  681. int err;
  682. err = devlink_info_driver_name_put(req, "mv88e6xxx");
  683. if (err)
  684. return err;
  685. return devlink_info_version_fixed_put(req,
  686. DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
  687. chip->info->name);
  688. }