ocelot_mrp.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2. /* Microsemi Ocelot Switch driver
  3. *
  4. * Copyright (c) 2017, 2019 Microsemi Corporation
  5. * Copyright 2020-2021 NXP
  6. */
  7. #include <linux/if_bridge.h>
  8. #include <linux/mrp_bridge.h>
  9. #include <soc/mscc/ocelot_vcap.h>
  10. #include <uapi/linux/mrp_bridge.h>
  11. #include "ocelot.h"
  12. #include "ocelot_vcap.h"
  13. static const u8 mrp_test_dmac[] = { 0x01, 0x15, 0x4e, 0x00, 0x00, 0x01 };
  14. static const u8 mrp_control_dmac[] = { 0x01, 0x15, 0x4e, 0x00, 0x00, 0x02 };
  15. static int ocelot_mrp_find_partner_port(struct ocelot *ocelot,
  16. struct ocelot_port *p)
  17. {
  18. int i;
  19. for (i = 0; i < ocelot->num_phys_ports; ++i) {
  20. struct ocelot_port *ocelot_port = ocelot->ports[i];
  21. if (!ocelot_port || p == ocelot_port)
  22. continue;
  23. if (ocelot_port->mrp_ring_id == p->mrp_ring_id)
  24. return i;
  25. }
  26. return -1;
  27. }
  28. static int ocelot_mrp_del_vcap(struct ocelot *ocelot, int id)
  29. {
  30. struct ocelot_vcap_block *block_vcap_is2;
  31. struct ocelot_vcap_filter *filter;
  32. block_vcap_is2 = &ocelot->block[VCAP_IS2];
  33. filter = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, id,
  34. false);
  35. if (!filter)
  36. return 0;
  37. return ocelot_vcap_filter_del(ocelot, filter);
  38. }
  39. static int ocelot_mrp_redirect_add_vcap(struct ocelot *ocelot, int src_port,
  40. int dst_port)
  41. {
  42. const u8 mrp_test_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  43. struct ocelot_vcap_filter *filter;
  44. int err;
  45. filter = kzalloc(sizeof(*filter), GFP_KERNEL);
  46. if (!filter)
  47. return -ENOMEM;
  48. filter->key_type = OCELOT_VCAP_KEY_ETYPE;
  49. filter->prio = 1;
  50. filter->id.cookie = OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, src_port);
  51. filter->id.tc_offload = false;
  52. filter->block_id = VCAP_IS2;
  53. filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
  54. filter->ingress_port_mask = BIT(src_port);
  55. ether_addr_copy(filter->key.etype.dmac.value, mrp_test_dmac);
  56. ether_addr_copy(filter->key.etype.dmac.mask, mrp_test_mask);
  57. filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT;
  58. filter->action.port_mask = BIT(dst_port);
  59. err = ocelot_vcap_filter_add(ocelot, filter, NULL);
  60. if (err)
  61. kfree(filter);
  62. return err;
  63. }
  64. static void ocelot_populate_mrp_trap_key(struct ocelot_vcap_filter *filter)
  65. {
  66. const u8 mrp_mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
  67. /* Here is possible to use control or test dmac because the mask
  68. * doesn't cover the LSB
  69. */
  70. ether_addr_copy(filter->key.etype.dmac.value, mrp_test_dmac);
  71. ether_addr_copy(filter->key.etype.dmac.mask, mrp_mask);
  72. }
  73. static int ocelot_mrp_trap_add(struct ocelot *ocelot, int port)
  74. {
  75. unsigned long cookie = OCELOT_VCAP_IS2_MRP_TRAP(ocelot);
  76. return ocelot_trap_add(ocelot, port, cookie, false,
  77. ocelot_populate_mrp_trap_key);
  78. }
  79. static int ocelot_mrp_trap_del(struct ocelot *ocelot, int port)
  80. {
  81. unsigned long cookie = OCELOT_VCAP_IS2_MRP_TRAP(ocelot);
  82. return ocelot_trap_del(ocelot, port, cookie);
  83. }
  84. static void ocelot_mrp_save_mac(struct ocelot *ocelot,
  85. struct ocelot_port *port)
  86. {
  87. ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_test_dmac,
  88. OCELOT_STANDALONE_PVID, ENTRYTYPE_LOCKED);
  89. ocelot_mact_learn(ocelot, PGID_BLACKHOLE, mrp_control_dmac,
  90. OCELOT_STANDALONE_PVID, ENTRYTYPE_LOCKED);
  91. }
  92. static void ocelot_mrp_del_mac(struct ocelot *ocelot,
  93. struct ocelot_port *port)
  94. {
  95. ocelot_mact_forget(ocelot, mrp_test_dmac, OCELOT_STANDALONE_PVID);
  96. ocelot_mact_forget(ocelot, mrp_control_dmac, OCELOT_STANDALONE_PVID);
  97. }
  98. int ocelot_mrp_add(struct ocelot *ocelot, int port,
  99. const struct switchdev_obj_mrp *mrp)
  100. {
  101. struct ocelot_port *ocelot_port = ocelot->ports[port];
  102. struct ocelot_port_private *priv;
  103. struct net_device *dev;
  104. if (!ocelot_port)
  105. return -EOPNOTSUPP;
  106. priv = container_of(ocelot_port, struct ocelot_port_private, port);
  107. dev = priv->dev;
  108. if (mrp->p_port != dev && mrp->s_port != dev)
  109. return 0;
  110. ocelot_port->mrp_ring_id = mrp->ring_id;
  111. return 0;
  112. }
  113. EXPORT_SYMBOL(ocelot_mrp_add);
  114. int ocelot_mrp_del(struct ocelot *ocelot, int port,
  115. const struct switchdev_obj_mrp *mrp)
  116. {
  117. struct ocelot_port *ocelot_port = ocelot->ports[port];
  118. if (!ocelot_port)
  119. return -EOPNOTSUPP;
  120. if (ocelot_port->mrp_ring_id != mrp->ring_id)
  121. return 0;
  122. ocelot_port->mrp_ring_id = 0;
  123. return 0;
  124. }
  125. EXPORT_SYMBOL(ocelot_mrp_del);
  126. int ocelot_mrp_add_ring_role(struct ocelot *ocelot, int port,
  127. const struct switchdev_obj_ring_role_mrp *mrp)
  128. {
  129. struct ocelot_port *ocelot_port = ocelot->ports[port];
  130. int dst_port;
  131. int err;
  132. if (!ocelot_port)
  133. return -EOPNOTSUPP;
  134. if (mrp->ring_role != BR_MRP_RING_ROLE_MRC && !mrp->sw_backup)
  135. return -EOPNOTSUPP;
  136. if (ocelot_port->mrp_ring_id != mrp->ring_id)
  137. return 0;
  138. ocelot_mrp_save_mac(ocelot, ocelot_port);
  139. if (mrp->ring_role != BR_MRP_RING_ROLE_MRC)
  140. return ocelot_mrp_trap_add(ocelot, port);
  141. dst_port = ocelot_mrp_find_partner_port(ocelot, ocelot_port);
  142. if (dst_port == -1)
  143. return -EINVAL;
  144. err = ocelot_mrp_redirect_add_vcap(ocelot, port, dst_port);
  145. if (err)
  146. return err;
  147. err = ocelot_mrp_trap_add(ocelot, port);
  148. if (err) {
  149. ocelot_mrp_del_vcap(ocelot,
  150. OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port));
  151. return err;
  152. }
  153. return 0;
  154. }
  155. EXPORT_SYMBOL(ocelot_mrp_add_ring_role);
  156. int ocelot_mrp_del_ring_role(struct ocelot *ocelot, int port,
  157. const struct switchdev_obj_ring_role_mrp *mrp)
  158. {
  159. struct ocelot_port *ocelot_port = ocelot->ports[port];
  160. int err, i;
  161. if (!ocelot_port)
  162. return -EOPNOTSUPP;
  163. if (mrp->ring_role != BR_MRP_RING_ROLE_MRC && !mrp->sw_backup)
  164. return -EOPNOTSUPP;
  165. if (ocelot_port->mrp_ring_id != mrp->ring_id)
  166. return 0;
  167. err = ocelot_mrp_trap_del(ocelot, port);
  168. if (err)
  169. return err;
  170. ocelot_mrp_del_vcap(ocelot, OCELOT_VCAP_IS2_MRP_REDIRECT(ocelot, port));
  171. for (i = 0; i < ocelot->num_phys_ports; ++i) {
  172. ocelot_port = ocelot->ports[i];
  173. if (!ocelot_port)
  174. continue;
  175. if (ocelot_port->mrp_ring_id != 0)
  176. goto out;
  177. }
  178. ocelot_mrp_del_mac(ocelot, ocelot->ports[port]);
  179. out:
  180. return 0;
  181. }
  182. EXPORT_SYMBOL(ocelot_mrp_del_ring_role);