+};
--- /dev/null
+++ b/drivers/net/ethernet/lantiq_xrx200.c
-@@ -0,0 +1,1810 @@
+@@ -0,0 +1,1830 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
++#include <linux/if_vlan.h>
+#include <asm/delay.h>
+
+#include <linux/of_net.h>
+
+#define SW_POLLING
+#define SW_ROUTING
-+/* #define SW_PORTMAP */
+
+#ifdef SW_ROUTING
-+ #ifdef SW_PORTMAP
+#define XRX200_MAX_DEV 2
-+ #else
-+#define XRX200_MAX_DEV 2
-+ #endif
+#else
+#define XRX200_MAX_DEV 1
+#endif
+ struct mii_bus *mii_bus;
+
+ struct xrx200_chan chan[XRX200_MAX_DMA];
++ u16 vlan_vid[XRX200_MAX_VLAN];
++ u16 vlan_port_map[XRX200_MAX_VLAN];
+
+ struct net_device *devs[XRX200_MAX_DEV];
+ int num_devs;
+static int xrx200sw_set_vlan_vid(struct switch_dev *dev, const struct switch_attr *attr,
+ struct switch_val *val)
+{
++ struct xrx200_hw *hw = container_of(dev, struct xrx200_hw, swdev);
+ int i;
+ struct xrx200_pce_table_entry tev;
+ struct xrx200_pce_table_entry tem;
+ return -EINVAL;
+ }
+
++ hw->vlan_vid[val->port_vlan] = val->value.i;
++
+ tev.index = val->port_vlan;
+ xrx200_pce_table_entry_read(&tev);
+ tev.key[0] = val->value.i;
+
+static int xrx200sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
+{
++ struct xrx200_hw *hw = container_of(dev, struct xrx200_hw, swdev);
+ int i, portmap, tagmap, untagged;
+ struct xrx200_pce_table_entry tem;
+
+ tem.val[2] = tagmap;
+ xrx200_pce_table_entry_write(&tem);
+
++ ltq_switch_w32_mask(0, portmap, PCE_PMAP2);
++ ltq_switch_w32_mask(0, portmap, PCE_PMAP3);
++ hw->vlan_port_map[val->port_vlan] = portmap;
++
+ xrx200sw_fixup_pvids();
+
+ return 0;
+ if (ret) {
+ netdev_err(dev,
+ "failed to allocate new rx buffer\n");
-+ return 0;
++ return;
+ }
+
+ skb_put(skb, len);
+ u32 byte_offset;
+ int len;
+#ifdef SW_ROUTING
-+ #ifdef SW_PORTMAP
-+ u32 special_tag = (SPID_CPU_PORT << SPID_SHIFT) | PORT_MAP_SEL | PORT_MAP_EN | DPID_ENABLE;
-+ #else
+ u32 special_tag = (SPID_CPU_PORT << SPID_SHIFT) | DPID_ENABLE;
-+ #endif
+#endif
+
+ skb->dev = dev;
+ return NETDEV_TX_BUSY;
+ }
+#ifdef SW_ROUTING
-+ #ifdef SW_PORTMAP
++ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
++ u16 port_map = priv->port_map;
++ special_tag |= PORT_MAP_SEL | PORT_MAP_EN;
++ if (skb->protocol == htons(ETH_P_8021Q)) {
++ u16 vid;
++ int i;
++
++ if (!__vlan_get_tag(skb, &vid)) {
++ for (i = 0; i < XRX200_MAX_VLAN; i++) {
++ if (priv->hw->vlan_vid[i] != vid)
++ continue;
++ port_map = priv->hw->vlan_port_map[i];
++ break;
++ }
++ }
++ }
++ special_tag |= port_map << PORT_MAP_SHIFT;
++ }
+ special_tag |= priv->port_map << PORT_MAP_SHIFT;
-+ #else
+ if(priv->id)
+ special_tag |= (1 << DPID_SHIFT);
-+ #endif
+ if(skb_headroom(skb) < 4) {
+ struct sk_buff *tmp = skb_realloc_headroom(skb, 4);
+ dev_kfree_skb_any(skb);
+ xrx200_pci_microcode();
+
+ /* Default unknown Broadcat/Multicast/Unicast port maps */
-+ ltq_switch_w32(0x7f, PCE_PMAP1);
-+ ltq_switch_w32(0x7f, PCE_PMAP2);
-+ ltq_switch_w32(0x7f, PCE_PMAP3);
++ ltq_switch_w32(0x40, PCE_PMAP1);
++ ltq_switch_w32(0x40, PCE_PMAP2);
++ ltq_switch_w32(0x40, PCE_PMAP3);
+
+ /* RMON Counter Enable for all physical ports */
+ for (i = 0; i < 7; i++)
+ ltq_switch_w32_mask(0, BIT(3), MAC_CTRL_REG(6, 2));
+ ltq_switch_w32(1518 + 8 + 4 * 2, MAC_FLEN_REG);
+ xrx200sw_write_x(1, XRX200_BM_QUEUE_GCTRL_GL_MOD, 0);
++
++ for (i = 0; i < XRX200_MAX_VLAN; i++)
++ hw->vlan_vid[i] = i;
+}
+
+static void xrx200_hw_cleanup(struct xrx200_hw *hw)