diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index d246647b3653..819289e5be4f 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3136,6 +3136,8 @@ static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port, for (i = 0; i < rocker->port_count; i++) { p = rocker->ports[i]; + if (!p) + continue; if (!rocker_port_is_bridged(p)) continue; if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) { @@ -3195,7 +3197,7 @@ static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port, for (i = 0; i < rocker->port_count; i++) { p = rocker->ports[i]; - if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) + if (p && test_bit(ntohs(vlan_id), p->vlan_bitmap)) ref++; } @@ -4162,35 +4164,6 @@ static int rocker_port_set_mac_address(struct net_device *dev, void *p) return 0; } -static int rocker_port_vlan_rx_add_vid(struct net_device *dev, - __be16 proto, u16 vid) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - int err; - - err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, 0, vid); - if (err) - return err; - - return rocker_port_router_mac(rocker_port, SWITCHDEV_TRANS_NONE, - 0, htons(vid)); -} - -static int rocker_port_vlan_rx_kill_vid(struct net_device *dev, - __be16 proto, u16 vid) -{ - struct rocker_port *rocker_port = netdev_priv(dev); - int err; - - err = rocker_port_router_mac(rocker_port, SWITCHDEV_TRANS_NONE, - ROCKER_OP_FLAG_REMOVE, htons(vid)); - if (err) - return err; - - return rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, - ROCKER_OP_FLAG_REMOVE, vid); -} - static int rocker_port_get_phys_port_name(struct net_device *dev, char *buf, size_t len) { @@ -4211,8 +4184,6 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_stop = rocker_port_stop, .ndo_start_xmit = rocker_port_xmit, .ndo_set_mac_address = rocker_port_set_mac_address, - .ndo_vlan_rx_add_vid = rocker_port_vlan_rx_add_vid, - .ndo_vlan_rx_kill_vid = rocker_port_vlan_rx_kill_vid, .ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, @@ -4320,7 +4291,12 @@ static int rocker_port_vlan_add(struct rocker_port *rocker_port, if (err) return err; - return rocker_port_router_mac(rocker_port, trans, 0, htons(vid)); + err = rocker_port_router_mac(rocker_port, trans, 0, htons(vid)); + if (err) + rocker_port_vlan(rocker_port, trans, + ROCKER_OP_FLAG_REMOVE, vid); + + return err; } static int rocker_port_vlans_add(struct rocker_port *rocker_port, @@ -4852,6 +4828,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) const struct pci_dev *pdev = rocker->pdev; struct rocker_port *rocker_port; struct net_device *dev; + u16 untagged_vid = 0; int err; dev = alloc_etherdev(sizeof(struct rocker_port)); @@ -4875,8 +4852,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) NAPI_POLL_WEIGHT); rocker_carrier_init(rocker_port); - dev->features |= NETIF_F_NETNS_LOCAL | - NETIF_F_HW_VLAN_CTAG_FILTER; + dev->features |= NETIF_F_NETNS_LOCAL; err = register_netdev(dev); if (err) { @@ -4887,16 +4863,27 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE); - rocker_port->internal_vlan_id = - rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex); err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0); if (err) { dev_err(&pdev->dev, "install ig port table failed\n"); goto err_port_ig_tbl; } + rocker_port->internal_vlan_id = + rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex); + + err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, + untagged_vid, 0); + if (err) { + netdev_err(rocker_port->dev, "install untagged VLAN failed\n"); + goto err_untagged_vlan; + } + return 0; +err_untagged_vlan: + rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, + ROCKER_OP_FLAG_REMOVE); err_port_ig_tbl: unregister_netdev(dev); err_register_netdev: @@ -4911,7 +4898,7 @@ static int rocker_probe_ports(struct rocker *rocker) int err; alloc_size = sizeof(struct rocker_port *) * rocker->port_count; - rocker->ports = kmalloc(alloc_size, GFP_KERNEL); + rocker->ports = kzalloc(alloc_size, GFP_KERNEL); if (!rocker->ports) return -ENOMEM; for (i = 0; i < rocker->port_count; i++) { @@ -5134,41 +5121,49 @@ static bool rocker_port_dev_check(const struct net_device *dev) static int rocker_port_bridge_join(struct rocker_port *rocker_port, struct net_device *bridge) { + u16 untagged_vid = 0; int err; + /* Port is joining bridge, so the internal VLAN for the + * port is going to change to the bridge internal VLAN. + * Let's remove untagged VLAN (vid=0) from port and + * re-add once internal VLAN has changed. + */ + + err = rocker_port_vlan_del(rocker_port, untagged_vid, 0); + if (err) + return err; + rocker_port_internal_vlan_id_put(rocker_port, rocker_port->dev->ifindex); + rocker_port->internal_vlan_id = + rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex); rocker_port->bridge_dev = bridge; - /* Use bridge internal VLAN ID for untagged pkts */ - err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, - ROCKER_OP_FLAG_REMOVE, 0); - if (err) - return err; - rocker_port->internal_vlan_id = - rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex); - return rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, 0, 0); + return rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, + untagged_vid, 0); } static int rocker_port_bridge_leave(struct rocker_port *rocker_port) { + u16 untagged_vid = 0; int err; + err = rocker_port_vlan_del(rocker_port, untagged_vid, 0); + if (err) + return err; + rocker_port_internal_vlan_id_put(rocker_port, rocker_port->bridge_dev->ifindex); - - rocker_port->bridge_dev = NULL; - - /* Use port internal VLAN ID for untagged pkts */ - err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, - ROCKER_OP_FLAG_REMOVE, 0); - if (err) - return err; rocker_port->internal_vlan_id = rocker_port_internal_vlan_id_get(rocker_port, rocker_port->dev->ifindex); - err = rocker_port_vlan(rocker_port, SWITCHDEV_TRANS_NONE, 0, 0); + + rocker_port->bridge_dev = NULL; + + err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, + untagged_vid, 0); if (err) return err;