lan966x_switchdev.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include <linux/if_bridge.h>
  3. #include <net/switchdev.h>
  4. #include "lan966x_main.h"
  5. static struct notifier_block lan966x_netdevice_nb __read_mostly;
  6. static void lan966x_port_set_mcast_ip_flood(struct lan966x_port *port,
  7. u32 pgid_ip)
  8. {
  9. struct lan966x *lan966x = port->lan966x;
  10. u32 flood_mask_ip;
  11. flood_mask_ip = lan_rd(lan966x, ANA_PGID(pgid_ip));
  12. flood_mask_ip = ANA_PGID_PGID_GET(flood_mask_ip);
  13. /* If mcast snooping is not enabled then use mcast flood mask
  14. * to decide to enable multicast flooding or not.
  15. */
  16. if (!port->mcast_ena) {
  17. u32 flood_mask;
  18. flood_mask = lan_rd(lan966x, ANA_PGID(PGID_MC));
  19. flood_mask = ANA_PGID_PGID_GET(flood_mask);
  20. if (flood_mask & BIT(port->chip_port))
  21. flood_mask_ip |= BIT(port->chip_port);
  22. else
  23. flood_mask_ip &= ~BIT(port->chip_port);
  24. } else {
  25. flood_mask_ip &= ~BIT(port->chip_port);
  26. }
  27. lan_rmw(ANA_PGID_PGID_SET(flood_mask_ip),
  28. ANA_PGID_PGID,
  29. lan966x, ANA_PGID(pgid_ip));
  30. }
  31. static void lan966x_port_set_mcast_flood(struct lan966x_port *port,
  32. bool enabled)
  33. {
  34. u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_MC));
  35. val = ANA_PGID_PGID_GET(val);
  36. if (enabled)
  37. val |= BIT(port->chip_port);
  38. else
  39. val &= ~BIT(port->chip_port);
  40. lan_rmw(ANA_PGID_PGID_SET(val),
  41. ANA_PGID_PGID,
  42. port->lan966x, ANA_PGID(PGID_MC));
  43. if (!port->mcast_ena) {
  44. lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV4);
  45. lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV6);
  46. }
  47. }
  48. static void lan966x_port_set_ucast_flood(struct lan966x_port *port,
  49. bool enabled)
  50. {
  51. u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_UC));
  52. val = ANA_PGID_PGID_GET(val);
  53. if (enabled)
  54. val |= BIT(port->chip_port);
  55. else
  56. val &= ~BIT(port->chip_port);
  57. lan_rmw(ANA_PGID_PGID_SET(val),
  58. ANA_PGID_PGID,
  59. port->lan966x, ANA_PGID(PGID_UC));
  60. }
  61. static void lan966x_port_set_bcast_flood(struct lan966x_port *port,
  62. bool enabled)
  63. {
  64. u32 val = lan_rd(port->lan966x, ANA_PGID(PGID_BC));
  65. val = ANA_PGID_PGID_GET(val);
  66. if (enabled)
  67. val |= BIT(port->chip_port);
  68. else
  69. val &= ~BIT(port->chip_port);
  70. lan_rmw(ANA_PGID_PGID_SET(val),
  71. ANA_PGID_PGID,
  72. port->lan966x, ANA_PGID(PGID_BC));
  73. }
  74. static void lan966x_port_set_learning(struct lan966x_port *port, bool enabled)
  75. {
  76. lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(enabled),
  77. ANA_PORT_CFG_LEARN_ENA,
  78. port->lan966x, ANA_PORT_CFG(port->chip_port));
  79. port->learn_ena = enabled;
  80. }
  81. static void lan966x_port_bridge_flags(struct lan966x_port *port,
  82. struct switchdev_brport_flags flags)
  83. {
  84. if (flags.mask & BR_MCAST_FLOOD)
  85. lan966x_port_set_mcast_flood(port,
  86. !!(flags.val & BR_MCAST_FLOOD));
  87. if (flags.mask & BR_FLOOD)
  88. lan966x_port_set_ucast_flood(port,
  89. !!(flags.val & BR_FLOOD));
  90. if (flags.mask & BR_BCAST_FLOOD)
  91. lan966x_port_set_bcast_flood(port,
  92. !!(flags.val & BR_BCAST_FLOOD));
  93. if (flags.mask & BR_LEARNING)
  94. lan966x_port_set_learning(port,
  95. !!(flags.val & BR_LEARNING));
  96. }
  97. static int lan966x_port_pre_bridge_flags(struct lan966x_port *port,
  98. struct switchdev_brport_flags flags)
  99. {
  100. if (flags.mask & ~(BR_MCAST_FLOOD | BR_FLOOD | BR_BCAST_FLOOD |
  101. BR_LEARNING))
  102. return -EINVAL;
  103. return 0;
  104. }
  105. void lan966x_update_fwd_mask(struct lan966x *lan966x)
  106. {
  107. int i;
  108. for (i = 0; i < lan966x->num_phys_ports; i++) {
  109. struct lan966x_port *port = lan966x->ports[i];
  110. unsigned long mask = 0;
  111. if (port && lan966x->bridge_fwd_mask & BIT(i)) {
  112. mask = lan966x->bridge_fwd_mask & ~BIT(i);
  113. if (port->bond)
  114. mask &= ~lan966x_lag_get_mask(lan966x,
  115. port->bond);
  116. }
  117. mask |= BIT(CPU_PORT);
  118. lan_wr(ANA_PGID_PGID_SET(mask),
  119. lan966x, ANA_PGID(PGID_SRC + i));
  120. }
  121. }
  122. void lan966x_port_stp_state_set(struct lan966x_port *port, u8 state)
  123. {
  124. struct lan966x *lan966x = port->lan966x;
  125. bool learn_ena = false;
  126. if ((state == BR_STATE_FORWARDING || state == BR_STATE_LEARNING) &&
  127. port->learn_ena)
  128. learn_ena = true;
  129. if (state == BR_STATE_FORWARDING)
  130. lan966x->bridge_fwd_mask |= BIT(port->chip_port);
  131. else
  132. lan966x->bridge_fwd_mask &= ~BIT(port->chip_port);
  133. lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(learn_ena),
  134. ANA_PORT_CFG_LEARN_ENA,
  135. lan966x, ANA_PORT_CFG(port->chip_port));
  136. lan966x_update_fwd_mask(lan966x);
  137. }
  138. void lan966x_port_ageing_set(struct lan966x_port *port,
  139. unsigned long ageing_clock_t)
  140. {
  141. unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
  142. u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
  143. lan966x_mac_set_ageing(port->lan966x, ageing_time);
  144. }
  145. static void lan966x_port_mc_set(struct lan966x_port *port, bool mcast_ena)
  146. {
  147. struct lan966x *lan966x = port->lan966x;
  148. port->mcast_ena = mcast_ena;
  149. if (mcast_ena)
  150. lan966x_mdb_restore_entries(lan966x);
  151. else
  152. lan966x_mdb_clear_entries(lan966x);
  153. lan_rmw(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_SET(mcast_ena) |
  154. ANA_CPU_FWD_CFG_MLD_REDIR_ENA_SET(mcast_ena) |
  155. ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_SET(mcast_ena),
  156. ANA_CPU_FWD_CFG_IGMP_REDIR_ENA |
  157. ANA_CPU_FWD_CFG_MLD_REDIR_ENA |
  158. ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA,
  159. lan966x, ANA_CPU_FWD_CFG(port->chip_port));
  160. lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV4);
  161. lan966x_port_set_mcast_ip_flood(port, PGID_MCIPV6);
  162. }
  163. static int lan966x_port_attr_set(struct net_device *dev, const void *ctx,
  164. const struct switchdev_attr *attr,
  165. struct netlink_ext_ack *extack)
  166. {
  167. struct lan966x_port *port = netdev_priv(dev);
  168. int err = 0;
  169. if (ctx && ctx != port)
  170. return 0;
  171. switch (attr->id) {
  172. case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
  173. lan966x_port_bridge_flags(port, attr->u.brport_flags);
  174. break;
  175. case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
  176. err = lan966x_port_pre_bridge_flags(port, attr->u.brport_flags);
  177. break;
  178. case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
  179. lan966x_port_stp_state_set(port, attr->u.stp_state);
  180. break;
  181. case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
  182. lan966x_port_ageing_set(port, attr->u.ageing_time);
  183. break;
  184. case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
  185. lan966x_vlan_port_set_vlan_aware(port, attr->u.vlan_filtering);
  186. lan966x_vlan_port_apply(port);
  187. break;
  188. case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED:
  189. lan966x_port_mc_set(port, !attr->u.mc_disabled);
  190. break;
  191. default:
  192. err = -EOPNOTSUPP;
  193. break;
  194. }
  195. return err;
  196. }
  197. static int lan966x_port_bridge_join(struct lan966x_port *port,
  198. struct net_device *brport_dev,
  199. struct net_device *bridge,
  200. struct netlink_ext_ack *extack)
  201. {
  202. struct switchdev_brport_flags flags = {0};
  203. struct lan966x *lan966x = port->lan966x;
  204. struct net_device *dev = port->dev;
  205. int err;
  206. if (!lan966x->bridge_mask) {
  207. lan966x->bridge = bridge;
  208. } else {
  209. if (lan966x->bridge != bridge) {
  210. NL_SET_ERR_MSG_MOD(extack, "Not allow to add port to different bridge");
  211. return -ENODEV;
  212. }
  213. }
  214. err = switchdev_bridge_port_offload(brport_dev, dev, port,
  215. &lan966x_switchdev_nb,
  216. &lan966x_switchdev_blocking_nb,
  217. false, extack);
  218. if (err)
  219. return err;
  220. lan966x->bridge_mask |= BIT(port->chip_port);
  221. flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
  222. flags.val = flags.mask;
  223. lan966x_port_bridge_flags(port, flags);
  224. return 0;
  225. }
  226. static void lan966x_port_bridge_leave(struct lan966x_port *port,
  227. struct net_device *bridge)
  228. {
  229. struct switchdev_brport_flags flags = {0};
  230. struct lan966x *lan966x = port->lan966x;
  231. flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
  232. flags.val = flags.mask & ~BR_LEARNING;
  233. lan966x_port_bridge_flags(port, flags);
  234. lan966x->bridge_mask &= ~BIT(port->chip_port);
  235. if (!lan966x->bridge_mask)
  236. lan966x->bridge = NULL;
  237. /* Set the port back to host mode */
  238. lan966x_vlan_port_set_vlan_aware(port, false);
  239. lan966x_vlan_port_set_vid(port, HOST_PVID, false, false);
  240. lan966x_vlan_port_apply(port);
  241. lan966x_vlan_port_rew_host(port);
  242. }
  243. int lan966x_port_changeupper(struct net_device *dev,
  244. struct net_device *brport_dev,
  245. struct netdev_notifier_changeupper_info *info)
  246. {
  247. struct lan966x_port *port = netdev_priv(dev);
  248. struct netlink_ext_ack *extack;
  249. int err = 0;
  250. extack = netdev_notifier_info_to_extack(&info->info);
  251. if (netif_is_bridge_master(info->upper_dev)) {
  252. if (info->linking)
  253. err = lan966x_port_bridge_join(port, brport_dev,
  254. info->upper_dev,
  255. extack);
  256. else
  257. lan966x_port_bridge_leave(port, info->upper_dev);
  258. }
  259. if (netif_is_lag_master(info->upper_dev)) {
  260. if (info->linking)
  261. err = lan966x_lag_port_join(port, info->upper_dev,
  262. info->upper_dev,
  263. extack);
  264. else
  265. lan966x_lag_port_leave(port, info->upper_dev);
  266. }
  267. return err;
  268. }
  269. int lan966x_port_prechangeupper(struct net_device *dev,
  270. struct net_device *brport_dev,
  271. struct netdev_notifier_changeupper_info *info)
  272. {
  273. struct lan966x_port *port = netdev_priv(dev);
  274. int err = NOTIFY_DONE;
  275. if (netif_is_bridge_master(info->upper_dev) && !info->linking) {
  276. switchdev_bridge_port_unoffload(port->dev, port, NULL, NULL);
  277. lan966x_fdb_flush_workqueue(port->lan966x);
  278. }
  279. if (netif_is_lag_master(info->upper_dev)) {
  280. err = lan966x_lag_port_prechangeupper(dev, info);
  281. if (err || info->linking)
  282. return err;
  283. switchdev_bridge_port_unoffload(brport_dev, port, NULL, NULL);
  284. lan966x_fdb_flush_workqueue(port->lan966x);
  285. }
  286. return err;
  287. }
  288. static int lan966x_foreign_bridging_check(struct net_device *upper,
  289. bool *has_foreign,
  290. bool *seen_lan966x,
  291. struct netlink_ext_ack *extack)
  292. {
  293. struct lan966x *lan966x = NULL;
  294. struct net_device *dev;
  295. struct list_head *iter;
  296. if (!netif_is_bridge_master(upper) &&
  297. !netif_is_lag_master(upper))
  298. return 0;
  299. netdev_for_each_lower_dev(upper, dev, iter) {
  300. if (lan966x_netdevice_check(dev)) {
  301. struct lan966x_port *port = netdev_priv(dev);
  302. if (lan966x) {
  303. /* Upper already has at least one port of a
  304. * lan966x switch inside it, check that it's
  305. * the same instance of the driver.
  306. */
  307. if (port->lan966x != lan966x) {
  308. NL_SET_ERR_MSG_MOD(extack,
  309. "Bridging between multiple lan966x switches disallowed");
  310. return -EINVAL;
  311. }
  312. } else {
  313. /* This is the first lan966x port inside this
  314. * upper device
  315. */
  316. lan966x = port->lan966x;
  317. *seen_lan966x = true;
  318. }
  319. } else if (netif_is_lag_master(dev)) {
  320. /* Allow to have bond interfaces that have only lan966x
  321. * devices
  322. */
  323. if (lan966x_foreign_bridging_check(dev, has_foreign,
  324. seen_lan966x,
  325. extack))
  326. return -EINVAL;
  327. } else {
  328. *has_foreign = true;
  329. }
  330. if (*seen_lan966x && *has_foreign) {
  331. NL_SET_ERR_MSG_MOD(extack,
  332. "Bridging lan966x ports with foreign interfaces disallowed");
  333. return -EINVAL;
  334. }
  335. }
  336. return 0;
  337. }
  338. static int lan966x_bridge_check(struct net_device *dev,
  339. struct netdev_notifier_changeupper_info *info)
  340. {
  341. bool has_foreign = false;
  342. bool seen_lan966x = false;
  343. return lan966x_foreign_bridging_check(info->upper_dev,
  344. &has_foreign,
  345. &seen_lan966x,
  346. info->info.extack);
  347. }
  348. static int lan966x_netdevice_port_event(struct net_device *dev,
  349. struct notifier_block *nb,
  350. unsigned long event, void *ptr)
  351. {
  352. int err = 0;
  353. if (!lan966x_netdevice_check(dev)) {
  354. switch (event) {
  355. case NETDEV_CHANGEUPPER:
  356. case NETDEV_PRECHANGEUPPER:
  357. err = lan966x_bridge_check(dev, ptr);
  358. if (err)
  359. return err;
  360. if (netif_is_lag_master(dev)) {
  361. if (event == NETDEV_CHANGEUPPER)
  362. err = lan966x_lag_netdev_changeupper(dev,
  363. ptr);
  364. else
  365. err = lan966x_lag_netdev_prechangeupper(dev,
  366. ptr);
  367. return err;
  368. }
  369. break;
  370. default:
  371. return 0;
  372. }
  373. return 0;
  374. }
  375. switch (event) {
  376. case NETDEV_PRECHANGEUPPER:
  377. err = lan966x_port_prechangeupper(dev, dev, ptr);
  378. break;
  379. case NETDEV_CHANGEUPPER:
  380. err = lan966x_bridge_check(dev, ptr);
  381. if (err)
  382. return err;
  383. err = lan966x_port_changeupper(dev, dev, ptr);
  384. break;
  385. case NETDEV_CHANGELOWERSTATE:
  386. err = lan966x_lag_port_changelowerstate(dev, ptr);
  387. break;
  388. }
  389. return err;
  390. }
  391. static int lan966x_netdevice_event(struct notifier_block *nb,
  392. unsigned long event, void *ptr)
  393. {
  394. struct net_device *dev = netdev_notifier_info_to_dev(ptr);
  395. int ret;
  396. ret = lan966x_netdevice_port_event(dev, nb, event, ptr);
  397. return notifier_from_errno(ret);
  398. }
  399. static bool lan966x_foreign_dev_check(const struct net_device *dev,
  400. const struct net_device *foreign_dev)
  401. {
  402. struct lan966x_port *port = netdev_priv(dev);
  403. struct lan966x *lan966x = port->lan966x;
  404. int i;
  405. if (netif_is_bridge_master(foreign_dev))
  406. if (lan966x->bridge == foreign_dev)
  407. return false;
  408. if (netif_is_lag_master(foreign_dev))
  409. for (i = 0; i < lan966x->num_phys_ports; ++i)
  410. if (lan966x->ports[i] &&
  411. lan966x->ports[i]->bond == foreign_dev)
  412. return false;
  413. return true;
  414. }
  415. static int lan966x_switchdev_event(struct notifier_block *nb,
  416. unsigned long event, void *ptr)
  417. {
  418. struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
  419. int err;
  420. switch (event) {
  421. case SWITCHDEV_PORT_ATTR_SET:
  422. err = switchdev_handle_port_attr_set(dev, ptr,
  423. lan966x_netdevice_check,
  424. lan966x_port_attr_set);
  425. return notifier_from_errno(err);
  426. case SWITCHDEV_FDB_ADD_TO_DEVICE:
  427. case SWITCHDEV_FDB_DEL_TO_DEVICE:
  428. err = switchdev_handle_fdb_event_to_device(dev, event, ptr,
  429. lan966x_netdevice_check,
  430. lan966x_foreign_dev_check,
  431. lan966x_handle_fdb);
  432. return notifier_from_errno(err);
  433. }
  434. return NOTIFY_DONE;
  435. }
  436. static int lan966x_handle_port_vlan_add(struct lan966x_port *port,
  437. const struct switchdev_obj *obj)
  438. {
  439. const struct switchdev_obj_port_vlan *v = SWITCHDEV_OBJ_PORT_VLAN(obj);
  440. struct lan966x *lan966x = port->lan966x;
  441. if (!netif_is_bridge_master(obj->orig_dev))
  442. lan966x_vlan_port_add_vlan(port, v->vid,
  443. v->flags & BRIDGE_VLAN_INFO_PVID,
  444. v->flags & BRIDGE_VLAN_INFO_UNTAGGED);
  445. else
  446. lan966x_vlan_cpu_add_vlan(lan966x, v->vid);
  447. return 0;
  448. }
  449. static int lan966x_handle_port_obj_add(struct net_device *dev, const void *ctx,
  450. const struct switchdev_obj *obj,
  451. struct netlink_ext_ack *extack)
  452. {
  453. struct lan966x_port *port = netdev_priv(dev);
  454. int err;
  455. if (ctx && ctx != port)
  456. return 0;
  457. switch (obj->id) {
  458. case SWITCHDEV_OBJ_ID_PORT_VLAN:
  459. err = lan966x_handle_port_vlan_add(port, obj);
  460. break;
  461. case SWITCHDEV_OBJ_ID_PORT_MDB:
  462. case SWITCHDEV_OBJ_ID_HOST_MDB:
  463. err = lan966x_handle_port_mdb_add(port, obj);
  464. break;
  465. default:
  466. err = -EOPNOTSUPP;
  467. break;
  468. }
  469. return err;
  470. }
  471. static int lan966x_handle_port_vlan_del(struct lan966x_port *port,
  472. const struct switchdev_obj *obj)
  473. {
  474. const struct switchdev_obj_port_vlan *v = SWITCHDEV_OBJ_PORT_VLAN(obj);
  475. struct lan966x *lan966x = port->lan966x;
  476. if (!netif_is_bridge_master(obj->orig_dev))
  477. lan966x_vlan_port_del_vlan(port, v->vid);
  478. else
  479. lan966x_vlan_cpu_del_vlan(lan966x, v->vid);
  480. return 0;
  481. }
  482. static int lan966x_handle_port_obj_del(struct net_device *dev, const void *ctx,
  483. const struct switchdev_obj *obj)
  484. {
  485. struct lan966x_port *port = netdev_priv(dev);
  486. int err;
  487. if (ctx && ctx != port)
  488. return 0;
  489. switch (obj->id) {
  490. case SWITCHDEV_OBJ_ID_PORT_VLAN:
  491. err = lan966x_handle_port_vlan_del(port, obj);
  492. break;
  493. case SWITCHDEV_OBJ_ID_PORT_MDB:
  494. case SWITCHDEV_OBJ_ID_HOST_MDB:
  495. err = lan966x_handle_port_mdb_del(port, obj);
  496. break;
  497. default:
  498. err = -EOPNOTSUPP;
  499. break;
  500. }
  501. return err;
  502. }
  503. static int lan966x_switchdev_blocking_event(struct notifier_block *nb,
  504. unsigned long event,
  505. void *ptr)
  506. {
  507. struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
  508. int err;
  509. switch (event) {
  510. case SWITCHDEV_PORT_OBJ_ADD:
  511. err = switchdev_handle_port_obj_add(dev, ptr,
  512. lan966x_netdevice_check,
  513. lan966x_handle_port_obj_add);
  514. return notifier_from_errno(err);
  515. case SWITCHDEV_PORT_OBJ_DEL:
  516. err = switchdev_handle_port_obj_del(dev, ptr,
  517. lan966x_netdevice_check,
  518. lan966x_handle_port_obj_del);
  519. return notifier_from_errno(err);
  520. case SWITCHDEV_PORT_ATTR_SET:
  521. err = switchdev_handle_port_attr_set(dev, ptr,
  522. lan966x_netdevice_check,
  523. lan966x_port_attr_set);
  524. return notifier_from_errno(err);
  525. }
  526. return NOTIFY_DONE;
  527. }
  528. static struct notifier_block lan966x_netdevice_nb __read_mostly = {
  529. .notifier_call = lan966x_netdevice_event,
  530. };
  531. struct notifier_block lan966x_switchdev_nb __read_mostly = {
  532. .notifier_call = lan966x_switchdev_event,
  533. };
  534. struct notifier_block lan966x_switchdev_blocking_nb __read_mostly = {
  535. .notifier_call = lan966x_switchdev_blocking_event,
  536. };
  537. void lan966x_register_notifier_blocks(void)
  538. {
  539. register_netdevice_notifier(&lan966x_netdevice_nb);
  540. register_switchdev_notifier(&lan966x_switchdev_nb);
  541. register_switchdev_blocking_notifier(&lan966x_switchdev_blocking_nb);
  542. }
  543. void lan966x_unregister_notifier_blocks(void)
  544. {
  545. unregister_switchdev_blocking_notifier(&lan966x_switchdev_blocking_nb);
  546. unregister_switchdev_notifier(&lan966x_switchdev_nb);
  547. unregister_netdevice_notifier(&lan966x_netdevice_nb);
  548. }