25
25
#include "sja1105_sgmii.h"
26
26
#include "sja1105_tas.h"
27
27
28
+ #define SJA1105_UNKNOWN_MULTICAST 0x010000000000ull
29
+
28
30
static const struct dsa_switch_ops sja1105_switch_ops ;
29
31
30
32
static void sja1105_hw_reset (struct gpio_desc * gpio , unsigned int pulse_len ,
@@ -42,15 +44,10 @@ static void
42
44
sja1105_port_allow_traffic (struct sja1105_l2_forwarding_entry * l2_fwd ,
43
45
int from , int to , bool allow )
44
46
{
45
- if (allow ) {
46
- l2_fwd [from ].bc_domain |= BIT (to );
47
+ if (allow )
47
48
l2_fwd [from ].reach_port |= BIT (to );
48
- l2_fwd [from ].fl_domain |= BIT (to );
49
- } else {
50
- l2_fwd [from ].bc_domain &= ~BIT (to );
49
+ else
51
50
l2_fwd [from ].reach_port &= ~BIT (to );
52
- l2_fwd [from ].fl_domain &= ~BIT (to );
53
- }
54
51
}
55
52
56
53
/* Structure used to temporarily transport device tree
@@ -220,17 +217,43 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
220
217
221
218
static int sja1105_init_static_fdb (struct sja1105_private * priv )
222
219
{
220
+ struct sja1105_l2_lookup_entry * l2_lookup ;
223
221
struct sja1105_table * table ;
222
+ int port ;
224
223
225
224
table = & priv -> static_config .tables [BLK_IDX_L2_LOOKUP ];
226
225
227
- /* We only populate the FDB table through dynamic
228
- * L2 Address Lookup entries
226
+ /* We only populate the FDB table through dynamic L2 Address Lookup
227
+ * entries, except for a special entry at the end which is a catch-all
228
+ * for unknown multicast and will be used to control flooding domain.
229
229
*/
230
230
if (table -> entry_count ) {
231
231
kfree (table -> entries );
232
232
table -> entry_count = 0 ;
233
233
}
234
+
235
+ if (!priv -> info -> can_limit_mcast_flood )
236
+ return 0 ;
237
+
238
+ table -> entries = kcalloc (1 , table -> ops -> unpacked_entry_size ,
239
+ GFP_KERNEL );
240
+ if (!table -> entries )
241
+ return - ENOMEM ;
242
+
243
+ table -> entry_count = 1 ;
244
+ l2_lookup = table -> entries ;
245
+
246
+ /* All L2 multicast addresses have an odd first octet */
247
+ l2_lookup [0 ].macaddr = SJA1105_UNKNOWN_MULTICAST ;
248
+ l2_lookup [0 ].mask_macaddr = SJA1105_UNKNOWN_MULTICAST ;
249
+ l2_lookup [0 ].lockeds = true;
250
+ l2_lookup [0 ].index = SJA1105_MAX_L2_LOOKUP_COUNT - 1 ;
251
+
252
+ /* Flood multicast to every port by default */
253
+ for (port = 0 ; port < priv -> ds -> num_ports ; port ++ )
254
+ if (!dsa_is_unused_port (priv -> ds , port ))
255
+ l2_lookup [0 ].destports |= BIT (port );
256
+
234
257
return 0 ;
235
258
}
236
259
@@ -390,6 +413,12 @@ static int sja1105_init_l2_forwarding(struct sja1105_private *priv)
390
413
391
414
sja1105_port_allow_traffic (l2fwd , i , upstream , true);
392
415
sja1105_port_allow_traffic (l2fwd , upstream , i , true);
416
+
417
+ l2fwd [i ].bc_domain = BIT (upstream );
418
+ l2fwd [i ].fl_domain = BIT (upstream );
419
+
420
+ l2fwd [upstream ].bc_domain |= BIT (i );
421
+ l2fwd [upstream ].fl_domain |= BIT (i );
393
422
}
394
423
/* Next 8 entries define VLAN PCP mapping from ingress to egress.
395
424
* Create a one-to-one mapping.
@@ -1514,6 +1543,12 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
1514
1543
*/
1515
1544
if (!(l2_lookup .destports & BIT (port )))
1516
1545
continue ;
1546
+
1547
+ /* We need to hide the FDB entry for unknown multicast */
1548
+ if (l2_lookup .macaddr == SJA1105_UNKNOWN_MULTICAST &&
1549
+ l2_lookup .mask_macaddr == SJA1105_UNKNOWN_MULTICAST )
1550
+ continue ;
1551
+
1517
1552
u64_to_ether_addr (l2_lookup .macaddr , macaddr );
1518
1553
1519
1554
/* We need to hide the dsa_8021q VLANs from the user. */
@@ -1605,12 +1640,12 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port,
1605
1640
case BR_STATE_LEARNING :
1606
1641
mac [port ].ingress = true;
1607
1642
mac [port ].egress = false;
1608
- mac [port ].dyn_learn = true ;
1643
+ mac [port ].dyn_learn = !!( priv -> learn_ena & BIT ( port )) ;
1609
1644
break ;
1610
1645
case BR_STATE_FORWARDING :
1611
1646
mac [port ].ingress = true;
1612
1647
mac [port ].egress = true;
1613
- mac [port ].dyn_learn = true ;
1648
+ mac [port ].dyn_learn = !!( priv -> learn_ena & BIT ( port )) ;
1614
1649
break ;
1615
1650
default :
1616
1651
dev_err (ds -> dev , "invalid STP state: %d\n" , state );
@@ -3239,6 +3274,169 @@ static void sja1105_port_policer_del(struct dsa_switch *ds, int port)
3239
3274
sja1105_static_config_reload (priv , SJA1105_BEST_EFFORT_POLICING );
3240
3275
}
3241
3276
3277
+ static int sja1105_port_set_learning (struct sja1105_private * priv , int port ,
3278
+ bool enabled )
3279
+ {
3280
+ struct sja1105_mac_config_entry * mac ;
3281
+ int rc ;
3282
+
3283
+ mac = priv -> static_config .tables [BLK_IDX_MAC_CONFIG ].entries ;
3284
+
3285
+ mac [port ].dyn_learn = !!(priv -> learn_ena & BIT (port ));
3286
+
3287
+ rc = sja1105_dynamic_config_write (priv , BLK_IDX_MAC_CONFIG , port ,
3288
+ & mac [port ], true);
3289
+ if (rc )
3290
+ return rc ;
3291
+
3292
+ if (enabled )
3293
+ priv -> learn_ena |= BIT (port );
3294
+ else
3295
+ priv -> learn_ena &= ~BIT (port );
3296
+
3297
+ return 0 ;
3298
+ }
3299
+
3300
+ /* Common function for unicast and broadcast flood configuration.
3301
+ * Flooding is configured between each {ingress, egress} port pair, and since
3302
+ * the bridge's semantics are those of "egress flooding", it means we must
3303
+ * enable flooding towards this port from all ingress ports that are in the
3304
+ * same bridge. In practice, we just enable flooding from all possible ingress
3305
+ * ports regardless of whether they're in the same bridge or not, since the
3306
+ * reach_port configuration will not allow flooded frames to leak across
3307
+ * bridging domains anyway.
3308
+ */
3309
+ static int sja1105_port_ucast_bcast_flood (struct sja1105_private * priv , int to ,
3310
+ struct switchdev_brport_flags flags )
3311
+ {
3312
+ struct sja1105_l2_forwarding_entry * l2_fwd ;
3313
+ int from , rc ;
3314
+
3315
+ l2_fwd = priv -> static_config .tables [BLK_IDX_L2_FORWARDING ].entries ;
3316
+
3317
+ for (from = 0 ; from < priv -> ds -> num_ports ; from ++ ) {
3318
+ if (dsa_is_unused_port (priv -> ds , from ))
3319
+ continue ;
3320
+ if (from == to )
3321
+ continue ;
3322
+
3323
+ /* Unicast */
3324
+ if (flags .mask & BR_FLOOD ) {
3325
+ if (flags .val & BR_FLOOD )
3326
+ l2_fwd [from ].fl_domain |= BIT (to );
3327
+ else
3328
+ l2_fwd [from ].fl_domain &= ~BIT (to );
3329
+ }
3330
+ /* Broadcast */
3331
+ if (flags .mask & BR_BCAST_FLOOD ) {
3332
+ if (flags .val & BR_BCAST_FLOOD )
3333
+ l2_fwd [from ].bc_domain |= BIT (to );
3334
+ else
3335
+ l2_fwd [from ].bc_domain &= ~BIT (to );
3336
+ }
3337
+
3338
+ rc = sja1105_dynamic_config_write (priv , BLK_IDX_L2_FORWARDING ,
3339
+ from , & l2_fwd [from ], true);
3340
+ if (rc < 0 )
3341
+ return rc ;
3342
+ }
3343
+
3344
+ return 0 ;
3345
+ }
3346
+
3347
+ static int sja1105_port_mcast_flood (struct sja1105_private * priv , int to ,
3348
+ struct switchdev_brport_flags flags ,
3349
+ struct netlink_ext_ack * extack )
3350
+ {
3351
+ struct sja1105_l2_lookup_entry * l2_lookup ;
3352
+ struct sja1105_table * table ;
3353
+ int match ;
3354
+
3355
+ table = & priv -> static_config .tables [BLK_IDX_L2_LOOKUP ];
3356
+ l2_lookup = table -> entries ;
3357
+
3358
+ for (match = 0 ; match < table -> entry_count ; match ++ )
3359
+ if (l2_lookup [match ].macaddr == SJA1105_UNKNOWN_MULTICAST &&
3360
+ l2_lookup [match ].mask_macaddr == SJA1105_UNKNOWN_MULTICAST )
3361
+ break ;
3362
+
3363
+ if (match == table -> entry_count ) {
3364
+ NL_SET_ERR_MSG_MOD (extack ,
3365
+ "Could not find FDB entry for unknown multicast" );
3366
+ return - ENOSPC ;
3367
+ }
3368
+
3369
+ if (flags .val & BR_MCAST_FLOOD )
3370
+ l2_lookup [match ].destports |= BIT (to );
3371
+ else
3372
+ l2_lookup [match ].destports &= ~BIT (to );
3373
+
3374
+ return sja1105_dynamic_config_write (priv , BLK_IDX_L2_LOOKUP ,
3375
+ l2_lookup [match ].index ,
3376
+ & l2_lookup [match ],
3377
+ true);
3378
+ }
3379
+
3380
+ static int sja1105_port_pre_bridge_flags (struct dsa_switch * ds , int port ,
3381
+ struct switchdev_brport_flags flags ,
3382
+ struct netlink_ext_ack * extack )
3383
+ {
3384
+ struct sja1105_private * priv = ds -> priv ;
3385
+
3386
+ if (flags .mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
3387
+ BR_BCAST_FLOOD ))
3388
+ return - EINVAL ;
3389
+
3390
+ if (flags .mask & (BR_FLOOD | BR_MCAST_FLOOD ) &&
3391
+ !priv -> info -> can_limit_mcast_flood ) {
3392
+ bool multicast = !!(flags .val & BR_MCAST_FLOOD );
3393
+ bool unicast = !!(flags .val & BR_FLOOD );
3394
+
3395
+ if (unicast != multicast ) {
3396
+ NL_SET_ERR_MSG_MOD (extack ,
3397
+ "This chip cannot configure multicast flooding independently of unicast" );
3398
+ return - EINVAL ;
3399
+ }
3400
+ }
3401
+
3402
+ return 0 ;
3403
+ }
3404
+
3405
+ static int sja1105_port_bridge_flags (struct dsa_switch * ds , int port ,
3406
+ struct switchdev_brport_flags flags ,
3407
+ struct netlink_ext_ack * extack )
3408
+ {
3409
+ struct sja1105_private * priv = ds -> priv ;
3410
+ int rc ;
3411
+
3412
+ if (flags .mask & BR_LEARNING ) {
3413
+ bool learn_ena = !!(flags .val & BR_LEARNING );
3414
+
3415
+ rc = sja1105_port_set_learning (priv , port , learn_ena );
3416
+ if (rc )
3417
+ return rc ;
3418
+ }
3419
+
3420
+ if (flags .mask & (BR_FLOOD | BR_BCAST_FLOOD )) {
3421
+ rc = sja1105_port_ucast_bcast_flood (priv , port , flags );
3422
+ if (rc )
3423
+ return rc ;
3424
+ }
3425
+
3426
+ /* For chips that can't offload BR_MCAST_FLOOD independently, there
3427
+ * is nothing to do here, we ensured the configuration is in sync by
3428
+ * offloading BR_FLOOD.
3429
+ */
3430
+ if (flags .mask & BR_MCAST_FLOOD && priv -> info -> can_limit_mcast_flood ) {
3431
+ rc = sja1105_port_mcast_flood (priv , port , flags ,
3432
+ extack );
3433
+ if (rc )
3434
+ return rc ;
3435
+ }
3436
+
3437
+ return 0 ;
3438
+ }
3439
+
3242
3440
static const struct dsa_switch_ops sja1105_switch_ops = {
3243
3441
.get_tag_protocol = sja1105_get_tag_protocol ,
3244
3442
.setup = sja1105_setup ,
@@ -3262,6 +3460,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
3262
3460
.port_fdb_del = sja1105_fdb_del ,
3263
3461
.port_bridge_join = sja1105_bridge_join ,
3264
3462
.port_bridge_leave = sja1105_bridge_leave ,
3463
+ .port_pre_bridge_flags = sja1105_port_pre_bridge_flags ,
3464
+ .port_bridge_flags = sja1105_port_bridge_flags ,
3265
3465
.port_stp_state_set = sja1105_bridge_stp_state_set ,
3266
3466
.port_vlan_filtering = sja1105_vlan_filtering ,
3267
3467
.port_vlan_add = sja1105_vlan_add ,
0 commit comments