Skip to content

Commit 6d2c186

Browse files
HoratiuVulturdavem330
authored andcommitted
net: lan966x: Add vlan support.
Extend the driver to support vlan filtering by implementing the switchdev calls SWITCHDEV_OBJ_ID_PORT_VLAN, SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING Signed-off-by: Horatiu Vultur <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cf2f608 commit 6d2c186

File tree

5 files changed

+448
-6
lines changed

5 files changed

+448
-6
lines changed

drivers/net/ethernet/microchip/lan966x/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o
77

88
lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
9-
lan966x_mac.o lan966x_ethtool.o lan966x_switchdev.o
9+
lan966x_mac.o lan966x_ethtool.o lan966x_switchdev.o \
10+
lan966x_vlan.o

drivers/net/ethernet/microchip/lan966x/lan966x_main.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,12 @@ static int lan966x_port_set_mac_address(struct net_device *dev, void *p)
108108
int ret;
109109

110110
/* Learn the new net device MAC address in the mac table. */
111-
ret = lan966x_mac_cpu_learn(lan966x, addr->sa_data, port->pvid);
111+
ret = lan966x_mac_cpu_learn(lan966x, addr->sa_data, HOST_PVID);
112112
if (ret)
113113
return ret;
114114

115115
/* Then forget the previous one. */
116-
ret = lan966x_mac_cpu_forget(lan966x, dev->dev_addr, port->pvid);
116+
ret = lan966x_mac_cpu_forget(lan966x, dev->dev_addr, HOST_PVID);
117117
if (ret)
118118
return ret;
119119

@@ -283,6 +283,12 @@ static void lan966x_ifh_set_ipv(void *ifh, u64 bypass)
283283
IFH_POS_IPV, IFH_LEN * 4, PACK, 0);
284284
}
285285

286+
static void lan966x_ifh_set_vid(void *ifh, u64 vid)
287+
{
288+
packing(ifh, &vid, IFH_POS_TCI + IFH_WID_TCI - 1,
289+
IFH_POS_TCI, IFH_LEN * 4, PACK, 0);
290+
}
291+
286292
static int lan966x_port_xmit(struct sk_buff *skb, struct net_device *dev)
287293
{
288294
struct lan966x_port *port = netdev_priv(dev);
@@ -294,6 +300,7 @@ static int lan966x_port_xmit(struct sk_buff *skb, struct net_device *dev)
294300
lan966x_ifh_set_port(ifh, BIT_ULL(port->chip_port));
295301
lan966x_ifh_set_qos_class(ifh, skb->priority >= 7 ? 0x7 : skb->priority);
296302
lan966x_ifh_set_ipv(ifh, skb->priority >= 7 ? 0x7 : skb->priority);
303+
lan966x_ifh_set_vid(ifh, skb_vlan_tag_get(skb));
297304

298305
return lan966x_port_ifh_xmit(skb, ifh, dev);
299306
}
@@ -575,13 +582,14 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
575582
port->dev = dev;
576583
port->lan966x = lan966x;
577584
port->chip_port = p;
578-
port->pvid = PORT_PVID;
579585
lan966x->ports[p] = port;
580586

581587
dev->max_mtu = ETH_MAX_MTU;
582588

583589
dev->netdev_ops = &lan966x_port_netdev_ops;
584590
dev->ethtool_ops = &lan966x_ethtool_ops;
591+
dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
592+
NETIF_F_HW_VLAN_STAG_TX;
585593
dev->needed_headroom = IFH_LEN * sizeof(u32);
586594

587595
eth_hw_addr_gen(dev, lan966x->base_mac, p + 1);
@@ -628,6 +636,10 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p,
628636
return err;
629637
}
630638

639+
lan966x_vlan_port_set_vlan_aware(port, 0);
640+
lan966x_vlan_port_set_vid(port, HOST_PVID, false, false);
641+
lan966x_vlan_port_apply(port);
642+
631643
return 0;
632644
}
633645

@@ -638,6 +650,8 @@ static void lan966x_init(struct lan966x *lan966x)
638650
/* MAC table initialization */
639651
lan966x_mac_init(lan966x);
640652

653+
lan966x_vlan_init(lan966x);
654+
641655
/* Flush queues */
642656
lan_wr(lan_rd(lan966x, QS_XTR_FLUSH) |
643657
GENMASK(1, 0),

drivers/net/ethernet/microchip/lan966x/lan966x_main.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define __LAN966X_MAIN_H__
55

66
#include <linux/etherdevice.h>
7+
#include <linux/if_vlan.h>
78
#include <linux/jiffies.h>
89
#include <linux/phy.h>
910
#include <linux/phylink.h>
@@ -22,7 +23,8 @@
2223
#define PGID_SRC 80
2324
#define PGID_ENTRIES 89
2425

25-
#define PORT_PVID 0
26+
#define UNAWARE_PVID 0
27+
#define HOST_PVID 4095
2628

2729
/* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO */
2830
#define QSYS_Q_RSRV 95
@@ -82,6 +84,9 @@ struct lan966x {
8284
struct list_head mac_entries;
8385
spinlock_t mac_lock; /* lock for mac_entries list */
8486

87+
u16 vlan_mask[VLAN_N_VID];
88+
DECLARE_BITMAP(cpu_vlan_mask, VLAN_N_VID);
89+
8590
/* stats */
8691
const struct lan966x_stat_layout *stats_layout;
8792
u32 num_stats;
@@ -113,6 +118,8 @@ struct lan966x_port {
113118

114119
u8 chip_port;
115120
u16 pvid;
121+
u16 vid;
122+
bool vlan_aware;
116123

117124
struct phylink_config phylink_config;
118125
struct phylink_pcs phylink_pcs;
@@ -166,6 +173,23 @@ int lan966x_mac_add_entry(struct lan966x *lan966x,
166173
void lan966x_mac_purge_entries(struct lan966x *lan966x);
167174
irqreturn_t lan966x_mac_irq_handler(struct lan966x *lan966x);
168175

176+
void lan966x_vlan_init(struct lan966x *lan966x);
177+
void lan966x_vlan_port_apply(struct lan966x_port *port);
178+
bool lan966x_vlan_cpu_member_cpu_vlan_mask(struct lan966x *lan966x, u16 vid);
179+
void lan966x_vlan_port_set_vlan_aware(struct lan966x_port *port,
180+
bool vlan_aware);
181+
int lan966x_vlan_port_set_vid(struct lan966x_port *port,
182+
u16 vid,
183+
bool pvid,
184+
bool untagged);
185+
void lan966x_vlan_port_add_vlan(struct lan966x_port *port,
186+
u16 vid,
187+
bool pvid,
188+
bool untagged);
189+
void lan966x_vlan_port_del_vlan(struct lan966x_port *port, u16 vid);
190+
void lan966x_vlan_cpu_add_vlan(struct lan966x *lan966x, u16 vid);
191+
void lan966x_vlan_cpu_del_vlan(struct lan966x *lan966x, u16 vid);
192+
169193
static inline void __iomem *lan_addr(void __iomem *base[],
170194
int id, int tinst, int tcnt,
171195
int gbase, int ginst,

drivers/net/ethernet/microchip/lan966x/lan966x_switchdev.c

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ static int lan966x_port_attr_set(struct net_device *dev, const void *ctx,
7373
case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
7474
lan966x_port_ageing_set(port, attr->u.ageing_time);
7575
break;
76+
case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
77+
lan966x_vlan_port_set_vlan_aware(port, attr->u.vlan_filtering);
78+
lan966x_vlan_port_apply(port);
79+
break;
7680
default:
7781
err = -EOPNOTSUPP;
7882
break;
@@ -120,7 +124,10 @@ static void lan966x_port_bridge_leave(struct lan966x_port *port,
120124
if (!lan966x->bridge_mask)
121125
lan966x->bridge = NULL;
122126

123-
lan966x_mac_cpu_learn(lan966x, port->dev->dev_addr, PORT_PVID);
127+
/* Set the port back to host mode */
128+
lan966x_vlan_port_set_vlan_aware(port, false);
129+
lan966x_vlan_port_set_vid(port, HOST_PVID, false, false);
130+
lan966x_vlan_port_apply(port);
124131
}
125132

126133
static int lan966x_port_changeupper(struct net_device *dev,
@@ -264,6 +271,91 @@ static int lan966x_switchdev_event(struct notifier_block *nb,
264271
return NOTIFY_DONE;
265272
}
266273

274+
static int lan966x_handle_port_vlan_add(struct lan966x_port *port,
275+
const struct switchdev_obj *obj)
276+
{
277+
const struct switchdev_obj_port_vlan *v = SWITCHDEV_OBJ_PORT_VLAN(obj);
278+
struct lan966x *lan966x = port->lan966x;
279+
280+
/* When adding a port to a vlan, we get a callback for the port but
281+
* also for the bridge. When get the callback for the bridge just bail
282+
* out. Then when the bridge is added to the vlan, then we get a
283+
* callback here but in this case the flags has set:
284+
* BRIDGE_VLAN_INFO_BRENTRY. In this case it means that the CPU
285+
* port is added to the vlan, so the broadcast frames and unicast frames
286+
* with dmac of the bridge should be foward to CPU.
287+
*/
288+
if (netif_is_bridge_master(obj->orig_dev) &&
289+
!(v->flags & BRIDGE_VLAN_INFO_BRENTRY))
290+
return 0;
291+
292+
if (!netif_is_bridge_master(obj->orig_dev))
293+
lan966x_vlan_port_add_vlan(port, v->vid,
294+
v->flags & BRIDGE_VLAN_INFO_PVID,
295+
v->flags & BRIDGE_VLAN_INFO_UNTAGGED);
296+
else
297+
lan966x_vlan_cpu_add_vlan(lan966x, v->vid);
298+
299+
return 0;
300+
}
301+
302+
static int lan966x_handle_port_obj_add(struct net_device *dev, const void *ctx,
303+
const struct switchdev_obj *obj,
304+
struct netlink_ext_ack *extack)
305+
{
306+
struct lan966x_port *port = netdev_priv(dev);
307+
int err;
308+
309+
if (ctx && ctx != port)
310+
return 0;
311+
312+
switch (obj->id) {
313+
case SWITCHDEV_OBJ_ID_PORT_VLAN:
314+
err = lan966x_handle_port_vlan_add(port, obj);
315+
break;
316+
default:
317+
err = -EOPNOTSUPP;
318+
break;
319+
}
320+
321+
return err;
322+
}
323+
324+
static int lan966x_handle_port_vlan_del(struct lan966x_port *port,
325+
const struct switchdev_obj *obj)
326+
{
327+
const struct switchdev_obj_port_vlan *v = SWITCHDEV_OBJ_PORT_VLAN(obj);
328+
struct lan966x *lan966x = port->lan966x;
329+
330+
if (!netif_is_bridge_master(obj->orig_dev))
331+
lan966x_vlan_port_del_vlan(port, v->vid);
332+
else
333+
lan966x_vlan_cpu_del_vlan(lan966x, v->vid);
334+
335+
return 0;
336+
}
337+
338+
static int lan966x_handle_port_obj_del(struct net_device *dev, const void *ctx,
339+
const struct switchdev_obj *obj)
340+
{
341+
struct lan966x_port *port = netdev_priv(dev);
342+
int err;
343+
344+
if (ctx && ctx != port)
345+
return 0;
346+
347+
switch (obj->id) {
348+
case SWITCHDEV_OBJ_ID_PORT_VLAN:
349+
err = lan966x_handle_port_vlan_del(port, obj);
350+
break;
351+
default:
352+
err = -EOPNOTSUPP;
353+
break;
354+
}
355+
356+
return err;
357+
}
358+
267359
static int lan966x_switchdev_blocking_event(struct notifier_block *nb,
268360
unsigned long event,
269361
void *ptr)
@@ -272,6 +364,16 @@ static int lan966x_switchdev_blocking_event(struct notifier_block *nb,
272364
int err;
273365

274366
switch (event) {
367+
case SWITCHDEV_PORT_OBJ_ADD:
368+
err = switchdev_handle_port_obj_add(dev, ptr,
369+
lan966x_netdevice_check,
370+
lan966x_handle_port_obj_add);
371+
return notifier_from_errno(err);
372+
case SWITCHDEV_PORT_OBJ_DEL:
373+
err = switchdev_handle_port_obj_del(dev, ptr,
374+
lan966x_netdevice_check,
375+
lan966x_handle_port_obj_del);
376+
return notifier_from_errno(err);
275377
case SWITCHDEV_PORT_ATTR_SET:
276378
err = switchdev_handle_port_attr_set(dev, ptr,
277379
lan966x_netdevice_check,

0 commit comments

Comments
 (0)