1 /* 2 * Handling of a single switch port 3 * 4 * Copyright (c) 2017 Savoir-faire Linux Inc. 5 * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 */ 12 13 #include <linux/if_bridge.h> 14 #include <linux/notifier.h> 15 16 #include "dsa_priv.h" 17 18 static int dsa_port_notify(struct dsa_port *dp, unsigned long e, void *v) 19 { 20 struct raw_notifier_head *nh = &dp->ds->dst->nh; 21 int err; 22 23 err = raw_notifier_call_chain(nh, e, v); 24 25 return notifier_to_errno(err); 26 } 27 28 int dsa_port_set_state(struct dsa_port *dp, u8 state, 29 struct switchdev_trans *trans) 30 { 31 struct dsa_switch *ds = dp->ds; 32 int port = dp->index; 33 34 if (switchdev_trans_ph_prepare(trans)) 35 return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; 36 37 if (ds->ops->port_stp_state_set) 38 ds->ops->port_stp_state_set(ds, port, state); 39 40 if (ds->ops->port_fast_age) { 41 /* Fast age FDB entries or flush appropriate forwarding database 42 * for the given port, if we are moving it from Learning or 43 * Forwarding state, to Disabled or Blocking or Listening state. 44 */ 45 46 if ((dp->stp_state == BR_STATE_LEARNING || 47 dp->stp_state == BR_STATE_FORWARDING) && 48 (state == BR_STATE_DISABLED || 49 state == BR_STATE_BLOCKING || 50 state == BR_STATE_LISTENING)) 51 ds->ops->port_fast_age(ds, port); 52 } 53 54 dp->stp_state = state; 55 56 return 0; 57 } 58 59 static void dsa_port_set_state_now(struct dsa_port *dp, u8 state) 60 { 61 int err; 62 63 err = dsa_port_set_state(dp, state, NULL); 64 if (err) 65 pr_err("DSA: failed to set STP state %u (%d)\n", state, err); 66 } 67 68 int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy) 69 { 70 u8 stp_state = dp->bridge_dev ? BR_STATE_BLOCKING : BR_STATE_FORWARDING; 71 struct dsa_switch *ds = dp->ds; 72 int port = dp->index; 73 int err; 74 75 if (ds->ops->port_enable) { 76 err = ds->ops->port_enable(ds, port, phy); 77 if (err) 78 return err; 79 } 80 81 dsa_port_set_state_now(dp, stp_state); 82 83 return 0; 84 } 85 86 void dsa_port_disable(struct dsa_port *dp, struct phy_device *phy) 87 { 88 struct dsa_switch *ds = dp->ds; 89 int port = dp->index; 90 91 dsa_port_set_state_now(dp, BR_STATE_DISABLED); 92 93 if (ds->ops->port_disable) 94 ds->ops->port_disable(ds, port, phy); 95 } 96 97 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) 98 { 99 struct dsa_notifier_bridge_info info = { 100 .sw_index = dp->ds->index, 101 .port = dp->index, 102 .br = br, 103 }; 104 int err; 105 106 /* Here the port is already bridged. Reflect the current configuration 107 * so that drivers can program their chips accordingly. 108 */ 109 dp->bridge_dev = br; 110 111 err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); 112 113 /* The bridging is rolled back on error */ 114 if (err) 115 dp->bridge_dev = NULL; 116 117 return err; 118 } 119 120 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) 121 { 122 struct dsa_notifier_bridge_info info = { 123 .sw_index = dp->ds->index, 124 .port = dp->index, 125 .br = br, 126 }; 127 int err; 128 129 /* Here the port is already unbridged. Reflect the current configuration 130 * so that drivers can program their chips accordingly. 131 */ 132 dp->bridge_dev = NULL; 133 134 err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_LEAVE, &info); 135 if (err) 136 pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); 137 138 /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, 139 * so allow it to be in BR_STATE_FORWARDING to be kept functional 140 */ 141 dsa_port_set_state_now(dp, BR_STATE_FORWARDING); 142 } 143 144 int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, 145 struct switchdev_trans *trans) 146 { 147 struct dsa_switch *ds = dp->ds; 148 149 /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ 150 if (switchdev_trans_ph_prepare(trans)) 151 return 0; 152 153 if (ds->ops->port_vlan_filtering) 154 return ds->ops->port_vlan_filtering(ds, dp->index, 155 vlan_filtering); 156 157 return 0; 158 } 159 160 int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, 161 struct switchdev_trans *trans) 162 { 163 unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock); 164 unsigned int ageing_time = jiffies_to_msecs(ageing_jiffies); 165 struct dsa_notifier_ageing_time_info info = { 166 .ageing_time = ageing_time, 167 .trans = trans, 168 }; 169 170 if (switchdev_trans_ph_prepare(trans)) 171 return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); 172 173 dp->ageing_time = ageing_time; 174 175 return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); 176 } 177 178 int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, 179 u16 vid) 180 { 181 struct dsa_notifier_fdb_info info = { 182 .sw_index = dp->ds->index, 183 .port = dp->index, 184 .addr = addr, 185 .vid = vid, 186 }; 187 188 return dsa_port_notify(dp, DSA_NOTIFIER_FDB_ADD, &info); 189 } 190 191 int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr, 192 u16 vid) 193 { 194 struct dsa_notifier_fdb_info info = { 195 .sw_index = dp->ds->index, 196 .port = dp->index, 197 .addr = addr, 198 .vid = vid, 199 200 }; 201 202 return dsa_port_notify(dp, DSA_NOTIFIER_FDB_DEL, &info); 203 } 204 205 int dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data) 206 { 207 struct dsa_switch *ds = dp->ds; 208 int port = dp->index; 209 210 if (!ds->ops->port_fdb_dump) 211 return -EOPNOTSUPP; 212 213 return ds->ops->port_fdb_dump(ds, port, cb, data); 214 } 215 216 int dsa_port_mdb_add(struct dsa_port *dp, 217 const struct switchdev_obj_port_mdb *mdb, 218 struct switchdev_trans *trans) 219 { 220 struct dsa_notifier_mdb_info info = { 221 .sw_index = dp->ds->index, 222 .port = dp->index, 223 .trans = trans, 224 .mdb = mdb, 225 }; 226 227 return dsa_port_notify(dp, DSA_NOTIFIER_MDB_ADD, &info); 228 } 229 230 int dsa_port_mdb_del(struct dsa_port *dp, 231 const struct switchdev_obj_port_mdb *mdb) 232 { 233 struct dsa_notifier_mdb_info info = { 234 .sw_index = dp->ds->index, 235 .port = dp->index, 236 .mdb = mdb, 237 }; 238 239 return dsa_port_notify(dp, DSA_NOTIFIER_MDB_DEL, &info); 240 } 241 242 int dsa_port_vlan_add(struct dsa_port *dp, 243 const struct switchdev_obj_port_vlan *vlan, 244 struct switchdev_trans *trans) 245 { 246 struct dsa_notifier_vlan_info info = { 247 .sw_index = dp->ds->index, 248 .port = dp->index, 249 .trans = trans, 250 .vlan = vlan, 251 }; 252 253 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_ADD, &info); 254 } 255 256 int dsa_port_vlan_del(struct dsa_port *dp, 257 const struct switchdev_obj_port_vlan *vlan) 258 { 259 struct dsa_notifier_vlan_info info = { 260 .sw_index = dp->ds->index, 261 .port = dp->index, 262 .vlan = vlan, 263 }; 264 265 return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); 266 } 267