minimal.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
  2. /* Copyright (c) 2016-2019 Mellanox Technologies. All rights reserved */
  3. #include <linux/netdevice.h>
  4. #include <linux/etherdevice.h>
  5. #include <linux/ethtool.h>
  6. #include <linux/i2c.h>
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/mod_devicetable.h>
  10. #include <linux/types.h>
  11. #include "core.h"
  12. #include "core_env.h"
  13. #include "i2c.h"
  14. static const char mlxsw_m_driver_name[] = "mlxsw_minimal";
  15. #define MLXSW_M_FWREV_MINOR 2000
  16. #define MLXSW_M_FWREV_SUBMINOR 1886
  17. static const struct mlxsw_fw_rev mlxsw_m_fw_rev = {
  18. .minor = MLXSW_M_FWREV_MINOR,
  19. .subminor = MLXSW_M_FWREV_SUBMINOR,
  20. };
  21. struct mlxsw_m_port;
  22. struct mlxsw_m_line_card {
  23. bool active;
  24. int module_to_port[];
  25. };
  26. struct mlxsw_m {
  27. struct mlxsw_m_port **ports;
  28. struct mlxsw_core *core;
  29. const struct mlxsw_bus_info *bus_info;
  30. u8 base_mac[ETH_ALEN];
  31. u8 max_ports;
  32. u8 max_modules_per_slot; /* Maximum number of modules per-slot. */
  33. u8 num_of_slots; /* Including the main board. */
  34. struct mlxsw_m_line_card **line_cards;
  35. };
  36. struct mlxsw_m_port {
  37. struct net_device *dev;
  38. struct mlxsw_m *mlxsw_m;
  39. u16 local_port;
  40. u8 slot_index;
  41. u8 module;
  42. u8 module_offset;
  43. };
  44. static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m)
  45. {
  46. char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
  47. int err;
  48. err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(spad), spad_pl);
  49. if (err)
  50. return err;
  51. mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_m->base_mac);
  52. return 0;
  53. }
  54. static int mlxsw_m_port_open(struct net_device *dev)
  55. {
  56. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
  57. struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
  58. return mlxsw_env_module_port_up(mlxsw_m->core, 0,
  59. mlxsw_m_port->module);
  60. }
  61. static int mlxsw_m_port_stop(struct net_device *dev)
  62. {
  63. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
  64. struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
  65. mlxsw_env_module_port_down(mlxsw_m->core, 0, mlxsw_m_port->module);
  66. return 0;
  67. }
  68. static struct devlink_port *
  69. mlxsw_m_port_get_devlink_port(struct net_device *dev)
  70. {
  71. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
  72. struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
  73. return mlxsw_core_port_devlink_port_get(mlxsw_m->core,
  74. mlxsw_m_port->local_port);
  75. }
  76. static const struct net_device_ops mlxsw_m_port_netdev_ops = {
  77. .ndo_open = mlxsw_m_port_open,
  78. .ndo_stop = mlxsw_m_port_stop,
  79. .ndo_get_devlink_port = mlxsw_m_port_get_devlink_port,
  80. };
  81. static void mlxsw_m_module_get_drvinfo(struct net_device *dev,
  82. struct ethtool_drvinfo *drvinfo)
  83. {
  84. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
  85. struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
  86. strscpy(drvinfo->driver, mlxsw_m->bus_info->device_kind,
  87. sizeof(drvinfo->driver));
  88. snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
  89. "%d.%d.%d",
  90. mlxsw_m->bus_info->fw_rev.major,
  91. mlxsw_m->bus_info->fw_rev.minor,
  92. mlxsw_m->bus_info->fw_rev.subminor);
  93. strscpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name,
  94. sizeof(drvinfo->bus_info));
  95. }
  96. static int mlxsw_m_get_module_info(struct net_device *netdev,
  97. struct ethtool_modinfo *modinfo)
  98. {
  99. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
  100. struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
  101. return mlxsw_env_get_module_info(netdev, core,
  102. mlxsw_m_port->slot_index,
  103. mlxsw_m_port->module, modinfo);
  104. }
  105. static int
  106. mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
  107. u8 *data)
  108. {
  109. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
  110. struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
  111. return mlxsw_env_get_module_eeprom(netdev, core,
  112. mlxsw_m_port->slot_index,
  113. mlxsw_m_port->module, ee, data);
  114. }
  115. static int
  116. mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
  117. const struct ethtool_module_eeprom *page,
  118. struct netlink_ext_ack *extack)
  119. {
  120. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
  121. struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
  122. return mlxsw_env_get_module_eeprom_by_page(core,
  123. mlxsw_m_port->slot_index,
  124. mlxsw_m_port->module,
  125. page, extack);
  126. }
  127. static int mlxsw_m_reset(struct net_device *netdev, u32 *flags)
  128. {
  129. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
  130. struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
  131. return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->slot_index,
  132. mlxsw_m_port->module,
  133. flags);
  134. }
  135. static int
  136. mlxsw_m_get_module_power_mode(struct net_device *netdev,
  137. struct ethtool_module_power_mode_params *params,
  138. struct netlink_ext_ack *extack)
  139. {
  140. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
  141. struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
  142. return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->slot_index,
  143. mlxsw_m_port->module,
  144. params, extack);
  145. }
  146. static int
  147. mlxsw_m_set_module_power_mode(struct net_device *netdev,
  148. const struct ethtool_module_power_mode_params *params,
  149. struct netlink_ext_ack *extack)
  150. {
  151. struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
  152. struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
  153. return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->slot_index,
  154. mlxsw_m_port->module,
  155. params->policy, extack);
  156. }
  157. static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
  158. .get_drvinfo = mlxsw_m_module_get_drvinfo,
  159. .get_module_info = mlxsw_m_get_module_info,
  160. .get_module_eeprom = mlxsw_m_get_module_eeprom,
  161. .get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
  162. .reset = mlxsw_m_reset,
  163. .get_module_power_mode = mlxsw_m_get_module_power_mode,
  164. .set_module_power_mode = mlxsw_m_set_module_power_mode,
  165. };
  166. static int
  167. mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u16 local_port,
  168. u8 *p_module, u8 *p_width, u8 *p_slot_index)
  169. {
  170. char pmlp_pl[MLXSW_REG_PMLP_LEN];
  171. int err;
  172. mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
  173. err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl);
  174. if (err)
  175. return err;
  176. *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
  177. *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
  178. *p_slot_index = mlxsw_reg_pmlp_slot_index_get(pmlp_pl, 0);
  179. return 0;
  180. }
  181. static int
  182. mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port)
  183. {
  184. struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
  185. char ppad_pl[MLXSW_REG_PPAD_LEN];
  186. u8 addr[ETH_ALEN];
  187. int err;
  188. mlxsw_reg_ppad_pack(ppad_pl, false, 0);
  189. err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl);
  190. if (err)
  191. return err;
  192. mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, addr);
  193. eth_hw_addr_gen(mlxsw_m_port->dev, addr, mlxsw_m_port->module + 1 +
  194. mlxsw_m_port->module_offset);
  195. return 0;
  196. }
  197. static bool mlxsw_m_port_created(struct mlxsw_m *mlxsw_m, u16 local_port)
  198. {
  199. return mlxsw_m->ports[local_port];
  200. }
  201. static int
  202. mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u16 local_port, u8 slot_index,
  203. u8 module)
  204. {
  205. struct mlxsw_m_port *mlxsw_m_port;
  206. struct net_device *dev;
  207. int err;
  208. err = mlxsw_core_port_init(mlxsw_m->core, local_port, slot_index,
  209. module + 1, false, 0, false,
  210. 0, mlxsw_m->base_mac,
  211. sizeof(mlxsw_m->base_mac));
  212. if (err) {
  213. dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n",
  214. local_port);
  215. return err;
  216. }
  217. dev = alloc_etherdev(sizeof(struct mlxsw_m_port));
  218. if (!dev) {
  219. err = -ENOMEM;
  220. goto err_alloc_etherdev;
  221. }
  222. SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev);
  223. dev_net_set(dev, mlxsw_core_net(mlxsw_m->core));
  224. mlxsw_m_port = netdev_priv(dev);
  225. mlxsw_m_port->dev = dev;
  226. mlxsw_m_port->mlxsw_m = mlxsw_m;
  227. mlxsw_m_port->local_port = local_port;
  228. mlxsw_m_port->module = module;
  229. mlxsw_m_port->slot_index = slot_index;
  230. /* Add module offset for line card. Offset for main board iz zero.
  231. * For line card in slot #n offset is calculated as (#n - 1)
  232. * multiplied by maximum modules number, which could be found on a line
  233. * card.
  234. */
  235. mlxsw_m_port->module_offset = mlxsw_m_port->slot_index ?
  236. (mlxsw_m_port->slot_index - 1) *
  237. mlxsw_m->max_modules_per_slot : 0;
  238. dev->netdev_ops = &mlxsw_m_port_netdev_ops;
  239. dev->ethtool_ops = &mlxsw_m_port_ethtool_ops;
  240. err = mlxsw_m_port_dev_addr_get(mlxsw_m_port);
  241. if (err) {
  242. dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n",
  243. mlxsw_m_port->local_port);
  244. goto err_dev_addr_get;
  245. }
  246. netif_carrier_off(dev);
  247. mlxsw_m->ports[local_port] = mlxsw_m_port;
  248. err = register_netdev(dev);
  249. if (err) {
  250. dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n",
  251. mlxsw_m_port->local_port);
  252. goto err_register_netdev;
  253. }
  254. mlxsw_core_port_eth_set(mlxsw_m->core, mlxsw_m_port->local_port,
  255. mlxsw_m_port, dev);
  256. return 0;
  257. err_register_netdev:
  258. mlxsw_m->ports[local_port] = NULL;
  259. err_dev_addr_get:
  260. free_netdev(dev);
  261. err_alloc_etherdev:
  262. mlxsw_core_port_fini(mlxsw_m->core, local_port);
  263. return err;
  264. }
  265. static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u16 local_port)
  266. {
  267. struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port];
  268. mlxsw_core_port_clear(mlxsw_m->core, local_port, mlxsw_m);
  269. unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */
  270. mlxsw_m->ports[local_port] = NULL;
  271. free_netdev(mlxsw_m_port->dev);
  272. mlxsw_core_port_fini(mlxsw_m->core, local_port);
  273. }
  274. static int*
  275. mlxsw_m_port_mapping_get(struct mlxsw_m *mlxsw_m, u8 slot_index, u8 module)
  276. {
  277. return &mlxsw_m->line_cards[slot_index]->module_to_port[module];
  278. }
  279. static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u16 local_port,
  280. u8 *last_module)
  281. {
  282. unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
  283. u8 module, width, slot_index;
  284. int *module_to_port;
  285. int err;
  286. /* Fill out to local port mapping array */
  287. err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module,
  288. &width, &slot_index);
  289. if (err)
  290. return err;
  291. /* Skip if line card has been already configured */
  292. if (mlxsw_m->line_cards[slot_index]->active)
  293. return 0;
  294. if (!width)
  295. return 0;
  296. /* Skip, if port belongs to the cluster */
  297. if (module == *last_module)
  298. return 0;
  299. *last_module = module;
  300. if (WARN_ON_ONCE(module >= max_ports))
  301. return -EINVAL;
  302. mlxsw_env_module_port_map(mlxsw_m->core, slot_index, module);
  303. module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, module);
  304. *module_to_port = local_port;
  305. return 0;
  306. }
  307. static void
  308. mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index, u8 module)
  309. {
  310. int *module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
  311. module);
  312. *module_to_port = -1;
  313. mlxsw_env_module_port_unmap(mlxsw_m->core, slot_index, module);
  314. }
  315. static int mlxsw_m_linecards_init(struct mlxsw_m *mlxsw_m)
  316. {
  317. unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
  318. char mgpir_pl[MLXSW_REG_MGPIR_LEN];
  319. u8 num_of_modules;
  320. int i, j, err;
  321. mlxsw_reg_mgpir_pack(mgpir_pl, 0);
  322. err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl);
  323. if (err)
  324. return err;
  325. mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &num_of_modules,
  326. &mlxsw_m->num_of_slots);
  327. /* If the system is modular, get the maximum number of modules per-slot.
  328. * Otherwise, get the maximum number of modules on the main board.
  329. */
  330. if (mlxsw_m->num_of_slots)
  331. mlxsw_m->max_modules_per_slot =
  332. mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl);
  333. else
  334. mlxsw_m->max_modules_per_slot = num_of_modules;
  335. /* Add slot for main board. */
  336. mlxsw_m->num_of_slots += 1;
  337. mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports),
  338. GFP_KERNEL);
  339. if (!mlxsw_m->ports)
  340. return -ENOMEM;
  341. mlxsw_m->line_cards = kcalloc(mlxsw_m->num_of_slots,
  342. sizeof(*mlxsw_m->line_cards),
  343. GFP_KERNEL);
  344. if (!mlxsw_m->line_cards) {
  345. err = -ENOMEM;
  346. goto err_kcalloc;
  347. }
  348. for (i = 0; i < mlxsw_m->num_of_slots; i++) {
  349. mlxsw_m->line_cards[i] =
  350. kzalloc(struct_size(mlxsw_m->line_cards[i],
  351. module_to_port,
  352. mlxsw_m->max_modules_per_slot),
  353. GFP_KERNEL);
  354. if (!mlxsw_m->line_cards[i]) {
  355. err = -ENOMEM;
  356. goto err_kmalloc_array;
  357. }
  358. /* Invalidate the entries of module to local port mapping array. */
  359. for (j = 0; j < mlxsw_m->max_modules_per_slot; j++)
  360. mlxsw_m->line_cards[i]->module_to_port[j] = -1;
  361. }
  362. return 0;
  363. err_kmalloc_array:
  364. for (i--; i >= 0; i--)
  365. kfree(mlxsw_m->line_cards[i]);
  366. kfree(mlxsw_m->line_cards);
  367. err_kcalloc:
  368. kfree(mlxsw_m->ports);
  369. return err;
  370. }
  371. static void mlxsw_m_linecards_fini(struct mlxsw_m *mlxsw_m)
  372. {
  373. int i = mlxsw_m->num_of_slots;
  374. for (i--; i >= 0; i--)
  375. kfree(mlxsw_m->line_cards[i]);
  376. kfree(mlxsw_m->line_cards);
  377. kfree(mlxsw_m->ports);
  378. }
  379. static void
  380. mlxsw_m_linecard_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index)
  381. {
  382. int i;
  383. for (i = mlxsw_m->max_modules_per_slot - 1; i >= 0; i--) {
  384. int *module_to_port;
  385. module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i);
  386. if (*module_to_port > 0)
  387. mlxsw_m_port_module_unmap(mlxsw_m, slot_index, i);
  388. }
  389. }
  390. static int
  391. mlxsw_m_linecard_ports_create(struct mlxsw_m *mlxsw_m, u8 slot_index)
  392. {
  393. int *module_to_port;
  394. int i, err;
  395. for (i = 0; i < mlxsw_m->max_modules_per_slot; i++) {
  396. module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i);
  397. if (*module_to_port > 0) {
  398. err = mlxsw_m_port_create(mlxsw_m, *module_to_port,
  399. slot_index, i);
  400. if (err)
  401. goto err_port_create;
  402. /* Mark slot as active */
  403. if (!mlxsw_m->line_cards[slot_index]->active)
  404. mlxsw_m->line_cards[slot_index]->active = true;
  405. }
  406. }
  407. return 0;
  408. err_port_create:
  409. for (i--; i >= 0; i--) {
  410. module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i);
  411. if (*module_to_port > 0 &&
  412. mlxsw_m_port_created(mlxsw_m, *module_to_port)) {
  413. mlxsw_m_port_remove(mlxsw_m, *module_to_port);
  414. /* Mark slot as inactive */
  415. if (mlxsw_m->line_cards[slot_index]->active)
  416. mlxsw_m->line_cards[slot_index]->active = false;
  417. }
  418. }
  419. return err;
  420. }
  421. static void
  422. mlxsw_m_linecard_ports_remove(struct mlxsw_m *mlxsw_m, u8 slot_index)
  423. {
  424. int i;
  425. for (i = 0; i < mlxsw_m->max_modules_per_slot; i++) {
  426. int *module_to_port = mlxsw_m_port_mapping_get(mlxsw_m,
  427. slot_index, i);
  428. if (*module_to_port > 0 &&
  429. mlxsw_m_port_created(mlxsw_m, *module_to_port)) {
  430. mlxsw_m_port_remove(mlxsw_m, *module_to_port);
  431. mlxsw_m_port_module_unmap(mlxsw_m, slot_index, i);
  432. }
  433. }
  434. }
  435. static int mlxsw_m_ports_module_map(struct mlxsw_m *mlxsw_m)
  436. {
  437. unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
  438. u8 last_module = max_ports;
  439. int i, err;
  440. for (i = 1; i < max_ports; i++) {
  441. err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module);
  442. if (err)
  443. return err;
  444. }
  445. return 0;
  446. }
  447. static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
  448. {
  449. int err;
  450. /* Fill out module to local port mapping array */
  451. err = mlxsw_m_ports_module_map(mlxsw_m);
  452. if (err)
  453. goto err_ports_module_map;
  454. /* Create port objects for each valid entry */
  455. err = mlxsw_m_linecard_ports_create(mlxsw_m, 0);
  456. if (err)
  457. goto err_linecard_ports_create;
  458. return 0;
  459. err_linecard_ports_create:
  460. err_ports_module_map:
  461. mlxsw_m_linecard_port_module_unmap(mlxsw_m, 0);
  462. return err;
  463. }
  464. static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
  465. {
  466. mlxsw_m_linecard_ports_remove(mlxsw_m, 0);
  467. }
  468. static void
  469. mlxsw_m_ports_remove_selected(struct mlxsw_core *mlxsw_core,
  470. bool (*selector)(void *priv, u16 local_port),
  471. void *priv)
  472. {
  473. struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
  474. struct mlxsw_linecard *linecard_priv = priv;
  475. struct mlxsw_m_line_card *linecard;
  476. linecard = mlxsw_m->line_cards[linecard_priv->slot_index];
  477. if (WARN_ON(!linecard->active))
  478. return;
  479. mlxsw_m_linecard_ports_remove(mlxsw_m, linecard_priv->slot_index);
  480. linecard->active = false;
  481. }
  482. static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
  483. {
  484. const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev;
  485. /* Validate driver and FW are compatible.
  486. * Do not check major version, since it defines chip type, while
  487. * driver is supposed to support any type.
  488. */
  489. if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev))
  490. return 0;
  491. dev_err(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n",
  492. rev->major, rev->minor, rev->subminor, rev->major,
  493. mlxsw_m_fw_rev.minor, mlxsw_m_fw_rev.subminor);
  494. return -EINVAL;
  495. }
  496. static void
  497. mlxsw_m_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
  498. {
  499. struct mlxsw_m_line_card *linecard;
  500. struct mlxsw_m *mlxsw_m = priv;
  501. int err;
  502. linecard = mlxsw_m->line_cards[slot_index];
  503. /* Skip if line card has been already configured during init */
  504. if (linecard->active)
  505. return;
  506. /* Fill out module to local port mapping array */
  507. err = mlxsw_m_ports_module_map(mlxsw_m);
  508. if (err)
  509. goto err_ports_module_map;
  510. /* Create port objects for each valid entry */
  511. err = mlxsw_m_linecard_ports_create(mlxsw_m, slot_index);
  512. if (err) {
  513. dev_err(mlxsw_m->bus_info->dev, "Failed to create port for line card at slot %d\n",
  514. slot_index);
  515. goto err_linecard_ports_create;
  516. }
  517. linecard->active = true;
  518. return;
  519. err_linecard_ports_create:
  520. err_ports_module_map:
  521. mlxsw_m_linecard_port_module_unmap(mlxsw_m, slot_index);
  522. }
  523. static void
  524. mlxsw_m_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
  525. {
  526. struct mlxsw_m_line_card *linecard;
  527. struct mlxsw_m *mlxsw_m = priv;
  528. linecard = mlxsw_m->line_cards[slot_index];
  529. if (WARN_ON(!linecard->active))
  530. return;
  531. mlxsw_m_linecard_ports_remove(mlxsw_m, slot_index);
  532. linecard->active = false;
  533. }
  534. static struct mlxsw_linecards_event_ops mlxsw_m_event_ops = {
  535. .got_active = mlxsw_m_got_active,
  536. .got_inactive = mlxsw_m_got_inactive,
  537. };
  538. static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
  539. const struct mlxsw_bus_info *mlxsw_bus_info,
  540. struct netlink_ext_ack *extack)
  541. {
  542. struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
  543. int err;
  544. mlxsw_m->core = mlxsw_core;
  545. mlxsw_m->bus_info = mlxsw_bus_info;
  546. err = mlxsw_m_fw_rev_validate(mlxsw_m);
  547. if (err)
  548. return err;
  549. err = mlxsw_m_base_mac_get(mlxsw_m);
  550. if (err) {
  551. dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n");
  552. return err;
  553. }
  554. err = mlxsw_m_linecards_init(mlxsw_m);
  555. if (err) {
  556. dev_err(mlxsw_m->bus_info->dev, "Failed to create line cards\n");
  557. return err;
  558. }
  559. err = mlxsw_linecards_event_ops_register(mlxsw_core,
  560. &mlxsw_m_event_ops, mlxsw_m);
  561. if (err) {
  562. dev_err(mlxsw_m->bus_info->dev, "Failed to register line cards operations\n");
  563. goto linecards_event_ops_register;
  564. }
  565. err = mlxsw_m_ports_create(mlxsw_m);
  566. if (err) {
  567. dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
  568. goto err_ports_create;
  569. }
  570. return 0;
  571. err_ports_create:
  572. mlxsw_linecards_event_ops_unregister(mlxsw_core,
  573. &mlxsw_m_event_ops, mlxsw_m);
  574. linecards_event_ops_register:
  575. mlxsw_m_linecards_fini(mlxsw_m);
  576. return err;
  577. }
  578. static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core)
  579. {
  580. struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
  581. mlxsw_m_ports_remove(mlxsw_m);
  582. mlxsw_linecards_event_ops_unregister(mlxsw_core,
  583. &mlxsw_m_event_ops, mlxsw_m);
  584. mlxsw_m_linecards_fini(mlxsw_m);
  585. }
  586. static const struct mlxsw_config_profile mlxsw_m_config_profile;
  587. static struct mlxsw_driver mlxsw_m_driver = {
  588. .kind = mlxsw_m_driver_name,
  589. .priv_size = sizeof(struct mlxsw_m),
  590. .init = mlxsw_m_init,
  591. .fini = mlxsw_m_fini,
  592. .ports_remove_selected = mlxsw_m_ports_remove_selected,
  593. .profile = &mlxsw_m_config_profile,
  594. };
  595. static const struct i2c_device_id mlxsw_m_i2c_id[] = {
  596. { "mlxsw_minimal", 0},
  597. { },
  598. };
  599. static struct i2c_driver mlxsw_m_i2c_driver = {
  600. .driver.name = "mlxsw_minimal",
  601. .class = I2C_CLASS_HWMON,
  602. .id_table = mlxsw_m_i2c_id,
  603. };
  604. static int __init mlxsw_m_module_init(void)
  605. {
  606. int err;
  607. err = mlxsw_core_driver_register(&mlxsw_m_driver);
  608. if (err)
  609. return err;
  610. err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver);
  611. if (err)
  612. goto err_i2c_driver_register;
  613. return 0;
  614. err_i2c_driver_register:
  615. mlxsw_core_driver_unregister(&mlxsw_m_driver);
  616. return err;
  617. }
  618. static void __exit mlxsw_m_module_exit(void)
  619. {
  620. mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver);
  621. mlxsw_core_driver_unregister(&mlxsw_m_driver);
  622. }
  623. module_init(mlxsw_m_module_init);
  624. module_exit(mlxsw_m_module_exit);
  625. MODULE_LICENSE("Dual BSD/GPL");
  626. MODULE_AUTHOR("Vadim Pasternak <[email protected]>");
  627. MODULE_DESCRIPTION("Mellanox minimal driver");
  628. MODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id);