diff --git a/target/linux/atheros/config-2.6.23 b/target/linux/atheros/config-2.6.23
index 2f69da0ba74..86824273e3a 100644
--- a/target/linux/atheros/config-2.6.23
+++ b/target/linux/atheros/config-2.6.23
@@ -134,6 +134,7 @@ CONFIG_MTD_REDBOOT_PARTS_READONLY=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_SLRAM is not set
 CONFIG_MTD_SPIFLASH=y
+CONFIG_MVSWITCH_PHY=y
 CONFIG_NEW_GPIO=y
 # CONFIG_NO_IOPORT is not set
 # CONFIG_PAGE_SIZE_16KB is not set
diff --git a/target/linux/atheros/patches-2.6.23/200-ar2313_enable_mvswitch.patch b/target/linux/atheros/patches-2.6.23/200-ar2313_enable_mvswitch.patch
new file mode 100644
index 00000000000..b209aee0c81
--- /dev/null
+++ b/target/linux/atheros/patches-2.6.23/200-ar2313_enable_mvswitch.patch
@@ -0,0 +1,38 @@
+Index: linux-2.6.23.16/drivers/net/ar2313/ar2313.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/ar2313/ar2313.c	2008-04-20 10:26:15.000000000 +0200
++++ linux-2.6.23.16/drivers/net/ar2313/ar2313.c	2008-04-20 10:26:16.000000000 +0200
+@@ -955,7 +955,7 @@
+ 				dev->stats.rx_bytes += skb->len;
+ 				skb->protocol = eth_type_trans(skb, dev);
+ 				/* pass the packet to upper layers */
+-				netif_rx(skb);
++				sp->rx(skb);
+ 
+ 				skb_new->dev = dev;
+ 				/* 16 bit align */
+@@ -1370,6 +1370,11 @@
+ 		return PTR_ERR(phydev);
+ 	}
+ 
++	if (phydev->netif_rx)
++		sp->rx = phydev->netif_rx;
++	else
++		sp->rx = netif_rx;
++
+ 	/* mask with MAC supported features */
+ 	phydev->supported &= (SUPPORTED_10baseT_Half
+ 		| SUPPORTED_10baseT_Full
+Index: linux-2.6.23.16/drivers/net/ar2313/ar2313.h
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/ar2313/ar2313.h	2008-04-20 10:26:15.000000000 +0200
++++ linux-2.6.23.16/drivers/net/ar2313/ar2313.h	2008-04-20 10:26:16.000000000 +0200
+@@ -107,6 +107,8 @@
+  */
+ struct ar2313_private {
+ 	struct net_device *dev;
++	int (*rx)(struct sk_buff *skb);
++
+ 	int version;
+ 	u32 mb[2];
+ 
diff --git a/target/linux/generic-2.6/config-2.6.23 b/target/linux/generic-2.6/config-2.6.23
index baac771313f..20efb3ce90d 100644
--- a/target/linux/generic-2.6/config-2.6.23
+++ b/target/linux/generic-2.6/config-2.6.23
@@ -734,6 +734,7 @@ CONFIG_MSDOS_PARTITION=y
 CONFIG_MTD_ROOTFS_ROOT_DEV=y
 CONFIG_MTD_ROOTFS_SPLIT=y
 # CONFIG_MTD_UBI is not set
+# CONFIG_MVSWITCH_PHY is not set
 # CONFIG_MWAVE is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NCP_FS is not set
diff --git a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c
new file mode 100644
index 00000000000..3e644c22327
--- /dev/null
+++ b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c
@@ -0,0 +1,405 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/if_vlan.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include "mvswitch.h"
+
+MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
+MODULE_AUTHOR("Felix Fietkau");
+MODULE_LICENSE("GPL");
+
+struct mvswitch_priv {
+	/* the driver's tx function */
+	int (*hardstart)(struct sk_buff *skb, struct net_device *dev);
+	struct vlan_group *grp;
+	u8 vlans[16];
+};
+
+#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv)
+
+static inline u16
+r16(struct phy_device *phydev, int addr, int reg)
+{
+	return phydev->bus->read(phydev->bus, addr, reg);
+}
+
+static inline void
+w16(struct phy_device *phydev, int addr, int reg, u16 val)
+{
+	phydev->bus->write(phydev->bus, addr, reg, val);
+}
+
+static int
+mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mvswitch_priv *priv;
+	struct vlan_ethhdr *eh;
+	char *buf = NULL;
+	u16 vid;
+
+	priv = dev->phy_ptr;
+	if (unlikely(!priv))
+		goto error;
+
+	if (unlikely(skb->len < 16))
+		goto error;
+
+	eh = (struct vlan_ethhdr *) skb->data;
+	if (be16_to_cpu(eh->h_vlan_proto) != 0x8100)
+		goto error;
+
+	vid = be16_to_cpu(eh->h_vlan_TCI) & VLAN_VID_MASK;
+	if (unlikely((vid > 15 || !priv->vlans[vid])))
+		goto error;
+
+	if (skb->len <= 64) {
+		if (pskb_expand_head(skb, 0, 68 - skb->len, GFP_ATOMIC)) {
+			if (net_ratelimit())
+				printk("%s: failed to expand/update skb for the switch\n", dev->name);
+			goto error;
+		}
+
+		buf = skb->data + 64;
+		skb->len = 68;
+	} else {
+		if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) {
+			if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC)) {
+				if (net_ratelimit())
+					printk("%s: failed to expand/update skb for the switch\n", dev->name);
+				goto error;
+			}
+		}
+		buf = skb_put(skb, 4);
+	}
+
+	/* move the ethernet header 4 bytes forward, overwriting the vlan tag */
+	memmove(skb->data + 4, skb->data, 12);
+	skb->data += 4;
+	skb->len -= 4;
+	skb->mac_header += 4;
+
+	if (!buf)
+		goto error;
+
+	/* append the tag */
+	*((u32 *) buf) = (
+		(0x80 << 24) |
+		((priv->vlans[vid] & 0x1f) << 16)
+	);
+
+	return priv->hardstart(skb, dev);
+
+error:
+	/* any errors? drop the packet! */
+	dev_kfree_skb_any(skb);
+	return 0;
+}
+
+static int
+mvswitch_mangle_rx(struct sk_buff *skb, int napi)
+{
+	struct mvswitch_priv *priv;
+	struct net_device *dev;
+	int vlan = -1;
+	unsigned char *buf;
+	int i;
+
+	dev = skb->dev;
+	if (!dev)
+		goto error;
+
+	priv = dev->phy_ptr;
+	if (!priv)
+		goto error;
+
+	if (!priv->grp)
+		goto error;
+
+	buf = skb->data + skb->len - 4;
+	if (buf[0] != 0x80)
+		goto error;
+
+	/* look for the vlan matching the incoming port */
+	for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) {
+		if ((1 << buf[1]) & priv->vlans[i])
+			vlan = i;
+	}
+
+	if (vlan == -1)
+		goto error;
+
+	if (napi)
+		return vlan_hwaccel_receive_skb(skb, priv->grp, vlan);
+	else
+		return vlan_hwaccel_rx(skb, priv->grp, vlan);
+
+error:
+	/* no vlan? eat the packet! */
+	dev_kfree_skb_any(skb);
+	return 0;
+}
+
+
+static int
+mvswitch_netif_rx(struct sk_buff *skb)
+{
+	return mvswitch_mangle_rx(skb, 0);
+}
+
+static int
+mvswitch_netif_receive_skb(struct sk_buff *skb)
+{
+	return mvswitch_mangle_rx(skb, 1);
+}
+
+
+static void
+mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+	struct mvswitch_priv *priv = dev->phy_ptr;
+	priv->grp = grp;
+}
+
+
+static int
+mvswitch_config_init(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+	struct net_device *dev = pdev->attached_dev;
+	u8 vlmap = 0;
+	int i;
+
+	if (!dev)
+		return -EINVAL;
+
+	printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name);
+	pdev->supported = ADVERTISED_100baseT_Full;
+	pdev->advertising = ADVERTISED_100baseT_Full;
+	dev->phy_ptr = priv;
+
+	/* initialize default vlans */
+	for (i = 0; i < MV_PORTS; i++)
+		priv->vlans[(i == MV_WANPORT ? 1 : 0)] |= (1 << i);
+
+	/* before entering reset, disable all ports */
+	for (i = 0; i < MV_PORTS; i++)
+		w16(pdev, MV_PORTREG(CONTROL, i), 0x00);
+
+	msleep(2); /* wait for the status change to settle in */
+
+	/* put the device in reset and set ATU flags */
+	w16(pdev, MV_SWITCHREG(ATU_CTRL),
+		MV_ATUCTL_RESET |
+		MV_ATUCTL_ATU_1K |
+		MV_ATUCTL_AGETIME(4080) /* maximum */
+	);
+
+	i = 100; /* timeout */
+	do {
+		if (!(r16(pdev, MV_SWITCHREG(ATU_CTRL)) & MV_ATUCTL_RESET))
+			break;
+		msleep(1);
+	} while (--i > 0);
+
+	if (!i) {
+		printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
+		return -ETIMEDOUT;
+	}
+
+	/* initialize the cpu port */
+	w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
+		MV_PORTCTRL_ENABLED |
+		MV_PORTCTRL_VLANTUN |
+		MV_PORTCTRL_RXTR |
+		MV_PORTCTRL_TXTR
+	);
+	/* wait for the phy change to settle in */
+	msleep(2);
+	for (i = 0; i < MV_PORTS; i++) {
+		u8 pvid = 0;
+		int j;
+
+		vlmap = 0;
+
+		/* look for the matching vlan */
+		for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) {
+			if (priv->vlans[j] & (1 << i)) {
+				vlmap = priv->vlans[j];
+				pvid = j;
+			}
+		}
+		/* leave port unconfigured if it's not part of a vlan */
+		if (!vlmap)
+			break;
+
+		/* add the cpu port to the allowed destinations list */
+		vlmap |= (1 << MV_CPUPORT);
+
+		/* take port out of its own vlan destination map */
+		vlmap &= ~(1 << i);
+
+		/* apply vlan settings */
+		w16(pdev, MV_PORTREG(VLANMAP, i),
+			MV_PORTVLAN_PORTS(vlmap) |
+			MV_PORTVLAN_ID(pvid)
+		);
+
+		/* re-enable port */
+		w16(pdev, MV_PORTREG(CONTROL, i), MV_PORTCTRL_ENABLED);
+	}
+
+	/* build the target list for the cpu port */
+	for (i = 0, vlmap = 0; i < ARRAY_SIZE(priv->vlans); i++)
+		vlmap |= priv->vlans[i];
+
+	w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
+		MV_PORTVLAN_PORTS(vlmap)
+	);
+
+	/* set the port association vector */
+	for (i = 0; i <= MV_PORTS; i++) {
+		w16(pdev, MV_PORTREG(ASSOC, i),
+			MV_PORTASSOC_PORTS(1 << i)
+		);
+	}
+
+	/* hook into the tx function */
+	priv->hardstart = dev->hard_start_xmit;
+	pdev->netif_receive_skb = mvswitch_netif_receive_skb;
+	pdev->netif_rx = mvswitch_netif_rx;
+	dev->hard_start_xmit = mvswitch_mangle_tx;
+	dev->vlan_rx_register = mvswitch_vlan_rx_register;
+	dev->features |= NETIF_F_HW_VLAN_RX;
+
+	return 0;
+}
+
+static int
+mvswitch_read_status(struct phy_device *phydev)
+{
+	phydev->speed = SPEED_100;
+	phydev->duplex = DUPLEX_FULL;
+	phydev->state = PHY_UP;
+	return 0;
+}
+
+static int
+mvswitch_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static void
+mvswitch_remove(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv = to_mvsw(pdev);
+	struct net_device *dev = pdev->attached_dev;
+
+	/* restore old xmit handler */
+	if (priv->hardstart && dev)
+		dev->hard_start_xmit = priv->hardstart;
+	dev->vlan_rx_register = NULL;
+	dev->vlan_rx_kill_vid = NULL;
+	dev->phy_ptr = NULL;
+	dev->features &= ~NETIF_F_HW_VLAN_RX;
+	kfree(priv);
+}
+
+static bool
+mvswitch_detect(struct mii_bus *bus, int addr)
+{
+	u16 reg;
+	int i;
+
+	/* we attach to phy id 31 to make sure that the late probe works */
+	if (addr != 31)
+		return false;
+
+	/* look for the switch on the bus */
+	reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
+	if (reg != MV_IDENT_VALUE)
+		return false;
+
+	/* 
+	 * Now that we've established that the switch actually exists, let's 
+	 * get rid of the competition :)
+	 */
+	for (i = 0; i < 31; i++) {
+		if (!bus->phy_map[i])
+			continue;
+
+		device_unregister(&bus->phy_map[i]->dev);
+		kfree(bus->phy_map[i]);
+		bus->phy_map[i] = NULL;
+	}
+
+	return true;
+}
+
+static int
+mvswitch_probe(struct phy_device *pdev)
+{
+	struct mvswitch_priv *priv;
+
+	priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	pdev->priv = priv;
+
+	return 0;
+}
+
+
+static struct phy_driver mvswitch_driver = {
+	.name		= "Marvell 88E6060",
+	.features	= PHY_BASIC_FEATURES,
+	.detect		= &mvswitch_detect,
+	.probe		= &mvswitch_probe,
+	.remove		= &mvswitch_remove,
+	.config_init	= &mvswitch_config_init,
+	.config_aneg	= &mvswitch_config_aneg,
+	.read_status	= &mvswitch_read_status,
+	.driver		= { .owner = THIS_MODULE,},
+};
+
+static int __init
+mvswitch_init(void)
+{
+	return phy_driver_register(&mvswitch_driver);
+}
+
+static void __exit
+mvswitch_exit(void)
+{
+	phy_driver_unregister(&mvswitch_driver);
+}
+
+module_init(mvswitch_init);
+module_exit(mvswitch_exit);
diff --git a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h
new file mode 100644
index 00000000000..b51e84a7312
--- /dev/null
+++ b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h
@@ -0,0 +1,104 @@
+/*
+ * Marvell 88E6060 switch driver
+ * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation
+ */
+#ifndef __MVSWITCH_H
+#define __MVSWITCH_H
+
+#define MV_PORTS	5
+#define MV_WANPORT	4
+#define MV_CPUPORT	5
+
+#define MV_BASE		0x10
+
+#define MV_PHYPORT_BASE		(MV_BASE + 0x0)
+#define MV_PHYPORT(_n)		(MV_PHYPORT_BASE + (_n))
+#define MV_SWITCHPORT_BASE	(MV_BASE + 0x8)
+#define MV_SWITCHPORT(_n)	(MV_SWITCHPORT_BASE + (_n))
+#define MV_SWITCHREGS		(MV_BASE + 0xf)
+
+enum {
+	MV_PHY_CONTROL      = 0x00,
+	MV_PHY_STATUS       = 0x01,
+	MV_PHY_IDENT0       = 0x02,
+	MV_PHY_IDENT1       = 0x03,
+	MV_PHY_ANEG         = 0x04,
+	MV_PHY_LINK_ABILITY = 0x05,
+	MV_PHY_ANEG_EXPAND  = 0x06,
+	MV_PHY_XMIT_NEXTP   = 0x07,
+	MV_PHY_LINK_NEXTP   = 0x08,
+	MV_PHY_CONTROL1     = 0x10,
+	MV_PHY_STATUS1      = 0x11,
+	MV_PHY_INTR_EN      = 0x12,
+	MV_PHY_INTR_STATUS  = 0x13,
+	MV_PHY_INTR_PORT    = 0x14,
+	MV_PHY_RECV_COUNTER = 0x15,
+	MV_PHY_LED_PARALLEL = 0x16,
+	MV_PHY_LED_STREAM   = 0x17,
+	MV_PHY_LED_CTRL     = 0x18,
+	MV_PHY_LED_OVERRIDE = 0x19,
+	MV_PHY_VCT_CTRL     = 0x1a,
+	MV_PHY_VCT_STATUS   = 0x1b,
+	MV_PHY_CONTROL2     = 0x1e
+};
+#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type
+
+enum {
+	MV_PORT_STATUS      = 0x00,
+	MV_PORT_IDENT       = 0x03,
+	MV_PORT_CONTROL     = 0x04,
+	MV_PORT_VLANMAP     = 0x06,
+	MV_PORT_ASSOC       = 0x0b,
+	MV_PORT_RXCOUNT     = 0x10,
+	MV_PORT_TXCOUNT     = 0x11,
+};
+#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type
+
+enum {
+	MV_PORTCTRL_BLOCK   =  (1 << 0),
+	MV_PORTCTRL_LEARN   =  (2 << 0),
+	MV_PORTCTRL_ENABLED =  (3 << 0),
+	MV_PORTCTRL_VLANTUN =  (1 << 7),	/* Enforce VLANs on packets */
+	MV_PORTCTRL_RXTR    =  (1 << 8),	/* Enable Marvell packet trailer for ingress */
+	MV_PORTCTRL_TXTR    = (1 << 14),	/* Enable Marvell packet trailer for egress */
+	MV_PORTCTRL_FORCEFL = (1 << 15),	/* force flow control */
+};
+
+#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12)
+#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f)
+
+#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f)
+#define MV_PORTASSOC_MONITOR	(1 << 15)
+
+enum {
+	MV_SWITCH_MAC0      = 0x01,
+	MV_SWITCH_MAC1      = 0x02,
+	MV_SWITCH_MAC2      = 0x03,
+	MV_SWITCH_CTRL      = 0x04,
+	MV_SWITCH_ATU_CTRL  = 0x0a,
+	MV_SWITCH_ATU_OP    = 0x0b,
+	MV_SWITCH_ATU_DATA  = 0x0c,
+	MV_SWITCH_ATU_MAC0  = 0x0d,
+	MV_SWITCH_ATU_MAC1  = 0x0e,
+	MV_SWITCH_ATU_MAC2  = 0x0f,
+};
+#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type
+
+enum {
+#define MV_ATUCTL_AGETIME(_n)	((((_n) / 16) & 0xff) << 4)
+	MV_ATUCTL_ATU_256   = (0 << 12),
+	MV_ATUCTL_ATU_512   = (1 << 12),
+	MV_ATUCTL_ATU_1K	= (2 << 12),
+	MV_ATUCTL_ATUMASK   = (3 << 12),
+	MV_ATUCTL_NO_LEARN  = (1 << 14),
+	MV_ATUCTL_RESET     = (1 << 15),
+}
+
+#define MV_IDENT_MASK		0xfff0
+#define MV_IDENT_VALUE		0x0600
+
+#endif
diff --git a/target/linux/generic-2.6/patches-2.6.23/630-phy_packets.patch b/target/linux/generic-2.6/patches-2.6.23/630-phy_packets.patch
new file mode 100644
index 00000000000..5d7f97195fb
--- /dev/null
+++ b/target/linux/generic-2.6/patches-2.6.23/630-phy_packets.patch
@@ -0,0 +1,47 @@
+Index: linux-2.6.23.16/drivers/net/phy/phy_device.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/phy/phy_device.c	2008-02-11 07:06:32.000000000 +0100
++++ linux-2.6.23.16/drivers/net/phy/phy_device.c	2008-04-20 05:42:28.000000000 +0200
+@@ -67,6 +67,8 @@
+ 	dev->bus = bus;
+ 
+ 	dev->state = PHY_DOWN;
++	dev->netif_receive_skb = &netif_receive_skb;
++	dev->netif_rx = &netif_rx;
+ 
+ 	spin_lock_init(&dev->lock);
+ 
+Index: linux-2.6.23.16/include/linux/phy.h
+===================================================================
+--- linux-2.6.23.16.orig/include/linux/phy.h	2008-04-20 04:40:31.000000000 +0200
++++ linux-2.6.23.16/include/linux/phy.h	2008-04-20 05:53:21.000000000 +0200
+@@ -289,6 +289,17 @@
+ 	void (*adjust_link)(struct net_device *dev);
+ 
+ 	void (*adjust_state)(struct net_device *dev);
++
++	/*
++	 * By default these point to the original functions
++	 * with the same name. adding them to the phy_device
++	 * allows the phy driver to override them for packet
++	 * mangling if the ethernet driver supports it
++	 * This is required to support some really horrible
++	 * switches such as the Marvell 88E6060
++	 */
++	int (*netif_receive_skb)(struct sk_buff *skb);
++	int (*netif_rx)(struct sk_buff *skb);
+ };
+ #define to_phy_device(d) container_of(d, struct phy_device, dev)
+ 
+Index: linux-2.6.23.16/include/linux/netdevice.h
+===================================================================
+--- linux-2.6.23.16.orig/include/linux/netdevice.h	2008-02-11 07:06:32.000000000 +0100
++++ linux-2.6.23.16/include/linux/netdevice.h	2008-04-20 06:33:25.000000000 +0200
+@@ -426,6 +426,7 @@
+ 	void			*ax25_ptr;	/* AX.25 specific data */
+ 	struct wireless_dev	*ieee80211_ptr;	/* IEEE 802.11 specific data,
+ 						   assign before registering */
++	void			*phy_ptr; /* PHY device specific data */
+ 
+ /*
+  * Cache line mostly used on receive path (including eth_type_trans())
diff --git a/target/linux/generic-2.6/patches-2.6.23/640-mvswitch.patch b/target/linux/generic-2.6/patches-2.6.23/640-mvswitch.patch
new file mode 100644
index 00000000000..15c6e481ff5
--- /dev/null
+++ b/target/linux/generic-2.6/patches-2.6.23/640-mvswitch.patch
@@ -0,0 +1,52 @@
+Index: linux-2.6.23.16/drivers/net/phy/Kconfig
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/phy/Kconfig	2008-04-20 07:31:20.000000000 +0200
++++ linux-2.6.23.16/drivers/net/phy/Kconfig	2008-04-20 08:57:26.000000000 +0200
+@@ -65,6 +65,12 @@
+ 	---help---
+ 	  Currently supports the ADM6996F switch
+ 
++config MVSWITCH_PHY
++	tristate "Driver for Marvell switches"
++	select VLAN_8021Q
++	---help---
++	  Currently supports the Marvell 88E6060 switch.
++
+ config FIXED_PHY
+ 	tristate "Drivers for PHY emulation on fixed speed/link"
+ 	---help---
+Index: linux-2.6.23.16/drivers/net/phy/Makefile
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/phy/Makefile	2008-04-20 07:31:20.000000000 +0200
++++ linux-2.6.23.16/drivers/net/phy/Makefile	2008-04-20 07:31:34.000000000 +0200
+@@ -13,4 +13,5 @@
+ obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
+ obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
+ obj-$(CONFIG_ADM6996_PHY)	+= adm6996.o
++obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
+ obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+Index: linux-2.6.23.16/drivers/net/phy/mdio_bus.c
+===================================================================
+--- linux-2.6.23.16.orig/drivers/net/phy/mdio_bus.c	2008-04-20 04:40:31.000000000 +0200
++++ linux-2.6.23.16/drivers/net/phy/mdio_bus.c	2008-04-20 07:34:08.000000000 +0200
+@@ -35,6 +35,12 @@
+ #include <asm/irq.h>
+ #include <asm/uaccess.h>
+ 
++static void mdio_dev_release(struct device *dev)
++{
++	/* nothing to do */
++}
++
++
+ /**
+  * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+  * @bus: target mii_bus
+@@ -85,6 +91,7 @@
+ 
+ 			phydev->dev.parent = bus->dev;
+ 			phydev->dev.bus = &mdio_bus_type;
++			phydev->dev.release = mdio_dev_release;
+ 			snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, i);
+ 
+ 			phydev->bus = bus;