]> git.ipfire.org Git - people/dweismueller/ipfire-2.x.git/commitdiff
kernel: update to 3.14.30.
authorArne Fitzenreiter <arne_f@ipfire.org>
Thu, 29 Jan 2015 06:47:16 +0000 (07:47 +0100)
committerArne Fitzenreiter <arne_f@ipfire.org>
Thu, 29 Jan 2015 06:47:16 +0000 (07:47 +0100)
config/kernel/kernel.config.armv5tel-ipfire-kirkwood
config/kernel/kernel.config.armv5tel-ipfire-multi
config/kernel/kernel.config.armv5tel-ipfire-rpi
config/kernel/kernel.config.i586-ipfire
config/kernel/kernel.config.i586-ipfire-pae
config/rootfiles/common/armv5tel/linux-multi
lfs/linux
src/patches/linux-3.14.x-lamobo-r1.patch [deleted file]

index ff09320c231584f64730fee513f7cb8f30f7c369..18ffcd77c739074dd887661fde4a3f31e4d47811 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.27 Kernel Configuration
+# Linux/arm 3.14.30 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
index 6c387b305e9b9e75dc7c45d7cc20253058d68f98..e3fa93e9d69f37be80c2a646bd150a813a536046 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.29 Kernel Configuration
+# Linux/arm 3.14.30 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_MIGHT_HAVE_PCI=y
@@ -2185,12 +2185,12 @@ CONFIG_MDIO_SUN4I=m
 CONFIG_MDIO_BUS_MUX=m
 CONFIG_MDIO_BUS_MUX_GPIO=m
 CONFIG_MDIO_BUS_MUX_MMIOREG=m
+CONFIG_GATEWORKS_GW16083=m
 CONFIG_B53=m
 CONFIG_B53_PHY_DRIVER=m
 # CONFIG_B53_MMAP_DRIVER is not set
 # CONFIG_B53_SRAB_DRIVER is not set
 CONFIG_B53_PHY_FIXUP=y
-CONFIG_GATEWORKS_GW16083=m
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
 CONFIG_PPP_BSDCOMP=m
index 7aef006a0e7a101d0e134582f5d5779710783926..17a7305ebd0df2c61f0f858fff7d6cceb39f4935 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.27 Kernel Configuration
+# Linux/arm 3.14.30 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
index 967ae6698ed9c3c735cba9d57b73609a3a6b43e6..87687d962ee66c37826bba30edbc38b0d3b1bb52 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.14.27 Kernel Configuration
+# Linux/x86 3.14.30 Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -421,8 +421,6 @@ CONFIG_X86_MCE_THRESHOLD=y
 # CONFIG_X86_MCE_INJECT is not set
 CONFIG_X86_THERMAL_VECTOR=y
 CONFIG_VM86=y
-CONFIG_X86_16BIT=y
-CONFIG_X86_ESPFIX32=y
 CONFIG_TOSHIBA=m
 CONFIG_I8K=m
 # CONFIG_X86_REBOOTFIXUPS is not set
index be7eb4aa26008f6cf00526053dee8d90350490ef..c5a437a59688d615af27b32a7fae0feedf9f0c5c 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.14.27 Kernel Configuration
+# Linux/x86 3.14.30 Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -431,8 +431,6 @@ CONFIG_X86_MCE_THRESHOLD=y
 # CONFIG_X86_MCE_INJECT is not set
 CONFIG_X86_THERMAL_VECTOR=y
 CONFIG_VM86=y
-CONFIG_X86_16BIT=y
-CONFIG_X86_ESPFIX32=y
 CONFIG_TOSHIBA=m
 CONFIG_I8K=m
 # CONFIG_X86_REBOOTFIXUPS is not set
index 1313d76a9fdca763b7c44346d5686f71a137979c..3ef35e05dd02f22cc1b5d9497fcd314d5f50ebf0 100644 (file)
@@ -112,6 +112,7 @@ boot/dtb-KVER-ipfire-multi
 #boot/dtb-KVER-ipfire-multi/sun7i-a20-bananapi.dtb
 #boot/dtb-KVER-ipfire-multi/sun7i-a20-cubieboard2.dtb
 #boot/dtb-KVER-ipfire-multi/sun7i-a20-cubietruck.dtb
+#boot/dtb-KVER-ipfire-multi/sun7i-a20-lamobo-r1.dtb
 #boot/dtb-KVER-ipfire-multi/sun7i-a20-olinuxino-micro.dtb
 #boot/dtb-KVER-ipfire-multi/sun7i-a20-pcduino3.dtb
 #boot/dtb-KVER-ipfire-multi/vexpress-v2p-ca15-tc1.dtb
@@ -1284,8 +1285,6 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/jme.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/marvell
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/marvell/mv643xx_eth.ko
-#lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/marvell/mvmdio.ko
-#lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/marvell/mvneta.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/marvell/skge.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/marvell/sky2.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ethernet/mellanox
@@ -1375,6 +1374,9 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/amd.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/at803x.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/b53
+#lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/b53/b53_common.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/b53/b53_mdio.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/bcm87xx.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/broadcom.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/cicada.ko
@@ -1385,6 +1387,7 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/lxt.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/marvell.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/mdio-bitbang.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/mdio-gpio.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/mdio-mux-gpio.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/mdio-mux-mmioreg.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/mdio-mux.ko
@@ -1395,6 +1398,7 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/realtek.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/smsc.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/ste10Xp.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/swconfig.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/phy/vitesse.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ppp
 #lib/modules/KVER-ipfire-multi/kernel/drivers/net/ppp/bsd_comp.ko
@@ -1628,7 +1632,6 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/rtc/rtc-max6900.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/rtc/rtc-moxart.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/rtc/rtc-msm6242.ko
-#lib/modules/KVER-ipfire-multi/kernel/drivers/rtc/rtc-mv.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/rtc/rtc-mxc.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/rtc/rtc-pcf2127.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/rtc/rtc-pcf8523.ko
index 2573d0a4d655b99be5e025f154f33ccc979d1d72..8295c4b833163672f2f9a4a72e0bb39321e4068e 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
 
 include Config
 
-VER        = 3.14.29
+VER        = 3.14.30
 
-RPI_PATCHES = 3.14.29-grsec-ipfire1
-A7M_PATCHES = 3.14.29-grsec-ipfire1
-GRS_PATCHES = grsecurity-3.0-3.14.29-201501182217.patch.xz
+RPI_PATCHES = 3.14.30-grsec-ipfire1
+A7M_PATCHES = 3.14.30-grsec-ipfire1
+GRS_PATCHES = grsecurity-3.0-3.14.30-201501272307.patch.xz
 
 THISAPP    = linux-$(VER)
 DL_FILE    = linux-$(VER).tar.xz
@@ -37,7 +37,7 @@ DIR_APP    = $(DIR_SRC)/$(THISAPP)
 CFLAGS     =
 CXXFLAGS   =
 
-PAK_VER    = 56
+PAK_VER    = 57
 DEPS      = ""
 
 VERSUFIX=ipfire$(KCFG)
@@ -77,10 +77,10 @@ rpi-patches-$(RPI_PATCHES).patch.xz         = $(URL_IPFIRE)/rpi-patches-$(RPI_PATCHES).
 arm7-multi-patches-$(A7M_PATCHES).patch.xz     = $(URL_IPFIRE)/arm7-multi-patches-$(A7M_PATCHES).patch.xz
 $(GRS_PATCHES)                                 = $(URL_IPFIRE)/$(GRS_PATCHES)
 
-$(DL_FILE)_MD5                                 = a745f70181b573a34579d685ca16370e
-rpi-patches-$(RPI_PATCHES).patch.xz_MD5                = a3eddb2183aea4f8fa82fff9ebc14df3
-arm7-multi-patches-$(A7M_PATCHES).patch.xz_MD5 = 45f550a7f0d8ee4d6a1aab53efc2ad05
-$(GRS_PATCHES)_MD5                             = c60550bc1b435412757497d771e280e9
+$(DL_FILE)_MD5                                 = 5926982f20bbef0988fca03b92fe43a5
+rpi-patches-$(RPI_PATCHES).patch.xz_MD5                = 983293824ca8e68ced3a097bc9bdefb5
+arm7-multi-patches-$(A7M_PATCHES).patch.xz_MD5 = efcfe5889f120d879387dd4ebe881587
+$(GRS_PATCHES)_MD5                             = d3c9518ca3d5f5225cd624f94116397a
 
 install : $(TARGET)
 
@@ -172,9 +172,6 @@ ifeq "$(KCFG)" "-multi"
        # Apply Arm7-multiarch kernel patches.
        cd $(DIR_APP) && xzcat $(DIR_DL)/arm7-multi-patches-$(A7M_PATCHES).patch.xz | patch -Np1
 
-       # After next kernel update this patch will included to arm7-multi patchset.
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.14.x-lamobo-r1.patch
-
        # Install switch api userspace header
        cd $(DIR_APP) && install -v -m644 include/uapi/linux/switch.h /usr/include/linux/
 endif
diff --git a/src/patches/linux-3.14.x-lamobo-r1.patch b/src/patches/linux-3.14.x-lamobo-r1.patch
deleted file mode 100644 (file)
index 4e604df..0000000
+++ /dev/null
@@ -1,5732 +0,0 @@
-diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
-index e7cba29..b695ccd 100644
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -293,6 +293,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
-       sun7i-a20-bananapi.dtb \
-       sun7i-a20-cubieboard2.dtb \
-       sun7i-a20-cubietruck.dtb \
-+      sun7i-a20-lamobo-r1.dtb \
-       sun7i-a20-olinuxino-micro.dtb \
-       sun7i-a20-pcduino3.dtb
- dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
-diff --git a/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
-new file mode 100644
-index 0000000..615b77f
---- /dev/null
-+++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
-@@ -0,0 +1,207 @@
-+/*
-+ * Copyright 2014 Zoltan HERPAI
-+ * Zoltan HERPAI <wigyori@uid0.hu>
-+ * Arne Fitzenreiter <arne_f@ipfire.org>
-+ *
-+ * The code contained herein is licensed under the GNU General Public
-+ * License. You may obtain a copy of the GNU General Public License
-+ * Version 2 or later at the following locations:
-+ *
-+ * http://www.opensource.org/licenses/gpl-license.html
-+ * http://www.gnu.org/copyleft/gpl.html
-+ */
-+
-+/dts-v1/;
-+/include/ "sun7i-a20.dtsi"
-+/include/ "sunxi-common-regulators.dtsi"
-+#include <dt-bindings/input/input.h>
-+
-+/ {
-+      model = "Lamobo-R1";
-+      compatible = "lamobo,lamobo-r1", "allwinner,sun7i-a20";
-+
-+      aliases {
-+              spi0 = &spi1;
-+              spi1 = &spi2;
-+      };
-+
-+      soc@01c00000 {
-+              spi1: spi@01c06000 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&spi1_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              spi2: spi@01c17000 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&spi2_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              mmc0: mmc@01c0f000 {
-+                      pinctrl-names = "default", "default";
-+                      pinctrl-0 = <&mmc0_pins_a>;
-+                      pinctrl-1 = <&mmc0_cd_pin_lamobo>;
-+                      cd-gpios = <&pio 7 10 0>; /* PH10 */
-+                      status = "okay";
-+              };
-+
-+              usbphy: phy@01c13400 {
-+                      usb1_vbus-supply = <&reg_usb1_vbus>;
-+                      usb2_vbus-supply = <&reg_usb2_vbus>;
-+                      status = "okay";
-+              };
-+
-+              ehci0: usb@01c14000 {
-+                      status = "okay";
-+              };
-+
-+              ohci0: usb@01c14400 {
-+                      status = "okay";
-+              };
-+
-+              ahci: sata@01c18000 {
-+                      target-supply = <&reg_ahci_5v>;
-+                      status = "okay";
-+              };
-+
-+              ehci1: usb@01c1c000 {
-+                      status = "okay";
-+              };
-+
-+              ohci1: usb@01c1c400 {
-+                      status = "okay";
-+              };
-+
-+              pinctrl@01c20800 {
-+                      led_pins_lamobo: led_pins@0 {
-+                              allwinner,pins = "PH24";
-+                              allwinner,function = "gpio_out";
-+                              allwinner,drive = <0>;
-+                              allwinner,pull = <0>;
-+                      };
-+
-+                      mmc0_cd_pin_lamobo: mmc0_cd_pin@0 {
-+                              allwinner,pins = "PH10";
-+                              allwinner,function = "gpio_in";
-+                              allwinner,drive = <0>;
-+                              allwinner,pull = <1>;
-+                      };
-+                      
-+                      gmac_power_pin_lamobo: gmac_power_pin@0 {
-+                              allwinner,pins = "PH23";
-+                              allwinner,function = "gpio_out";
-+                              allwinner,drive = <0>;
-+                              allwinner,pull = <0>;
-+                      };
-+              };
-+
-+              lradc: lradc@01c22800 {
-+                      allwinner,chan0-step = <200>;
-+                      linux,chan0-keycodes = <KEY_VOLUMEUP KEY_VOLUMEDOWN
-+                                              KEY_MENU KEY_SEARCH KEY_HOME
-+                                              KEY_ESC KEY_ENTER>;
-+                      status = "okay";
-+              };
-+
-+              ir0: ir@01c21800 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&ir0_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              uart0: serial@01c28000 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&uart0_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              uart6: serial@01c29800 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&uart6_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              uart7: serial@01c29c00 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&uart7_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              i2c0: i2c@01c2ac00 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&i2c0_pins_a>;
-+                      status = "okay";
-+
-+                      axp: axp20x@34 {
-+                              reg = <0x34>;
-+                              interrupt-parent = <&nmi_intc>;
-+                              interrupts = <0 8>;
-+                              axp,system-power-controller;
-+                              /include/ "x-powers-axp209.dtsi"
-+                      };
-+              };
-+
-+              i2c1: i2c@01c2b000 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&i2c1_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              i2c2: i2c@01c2b400 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&i2c2_pins_a>;
-+                      status = "okay";
-+              };
-+
-+              gmac: ethernet@01c50000 {
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&gmac_pins_rgmii_a>;
-+                      phy = <&phy1>;
-+                      phy-mode = "rgmii";
-+                      phy-supply = <&reg_gmac_3v3>;
-+                      status = "okay";
-+
-+                      phy1: ethernet-phy@1 {
-+                              reg = <1>;
-+                      };
-+              };
-+      };
-+
-+      leds {
-+              compatible = "gpio-leds";
-+              pinctrl-names = "default";
-+              pinctrl-0 = <&led_pins_lamobo>;
-+
-+              green {
-+                      label = "lamobo:green:usr";
-+                      gpios = <&pio 7 24 0>;
-+                      linux,default-trigger = "heartbeat";
-+              };
-+      };
-+
-+        reg_ahci_5v: ahci-5v {
-+                status = "okay";
-+        };
-+
-+        reg_usb1_vbus: usb1-vbus {
-+                status = "okay";
-+        };
-+
-+        reg_usb2_vbus: usb2-vbus {
-+                status = "okay";
-+        };
-+
-+      reg_gmac_3v3: gmac-3v3 {
-+                      compatible = "regulator-fixed";
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&gmac_power_pin_lamobo>;
-+                      regulator-name = "gmac-3v3";
-+                      regulator-min-microvolt = <3300000>;
-+                      regulator-max-microvolt = <3300000>;
-+                      startup-delay-us = <50000>;
-+                      enable-active-high;
-+                      gpio = <&pio 7 23 0>;
-+                      status = "okay";
-+      };
-+};
-diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
-index 9b5d46c..3fe9c4d 100644
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -12,6 +12,16 @@ menuconfig PHYLIB
- if PHYLIB
-+config SWCONFIG
-+      tristate "Switch configuration API"
-+      ---help---
-+        Switch configuration API using netlink. This allows
-+        you to configure the VLAN features of certain switches.
-+
-+config SWCONFIG_LEDS
-+      bool "Switch LED trigger support"
-+      depends on (SWCONFIG && LEDS_TRIGGERS)
-+
- comment "MII PHY device drivers"
- config AT803X_PHY
-@@ -193,6 +203,8 @@ config MDIO_BUS_MUX_MMIOREG
-         Currently, only 8-bit registers are supported.
-+source "drivers/net/phy/b53/Kconfig"
-+
- endif # PHYLIB
- config MICREL_KS8995MA
-diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
-index 9013dfa..d5c5c50 100644
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -3,6 +3,7 @@
- libphy-objs                   := phy.o phy_device.o mdio_bus.o
- obj-$(CONFIG_PHYLIB)          += libphy.o
-+obj-$(CONFIG_SWCONFIG)                += swconfig.o
- obj-$(CONFIG_MARVELL_PHY)     += marvell.o
- obj-$(CONFIG_DAVICOM_PHY)     += davicom.o
- obj-$(CONFIG_CICADA_PHY)      += cicada.o
-@@ -16,6 +17,7 @@ obj-$(CONFIG_BCM87XX_PHY)    += bcm87xx.o
- obj-$(CONFIG_ICPLUS_PHY)      += icplus.o
- obj-$(CONFIG_REALTEK_PHY)     += realtek.o
- obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
-+obj-$(CONFIG_B53)             += b53/
- obj-$(CONFIG_FIXED_PHY)               += fixed.o
- obj-$(CONFIG_MDIO_BITBANG)    += mdio-bitbang.o
- obj-$(CONFIG_MDIO_GPIO)               += mdio-gpio.o
-diff --git a/drivers/net/phy/b53/Kconfig b/drivers/net/phy/b53/Kconfig
-new file mode 100644
-index 0000000..67e053e
---- /dev/null
-+++ b/drivers/net/phy/b53/Kconfig
-@@ -0,0 +1,37 @@
-+menuconfig B53
-+      tristate "Broadcom bcm53xx managed switch support"
-+      depends on SWCONFIG
-+      help
-+        This driver adds support for Broadcom managed switch chips. It supports
-+        BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
-+        integrated switches.
-+
-+config B53_SPI_DRIVER
-+      tristate "B53 SPI connected switch driver"
-+      depends on B53 && SPI
-+      help
-+        Select to enable support for registering switches configured through SPI.
-+
-+config B53_PHY_DRIVER
-+      tristate "B53 MDIO connected switch driver"
-+      depends on B53
-+      select B53_PHY_FIXUP
-+      help
-+        Select to enable support for registering switches configured through MDIO.
-+
-+config B53_MMAP_DRIVER
-+      tristate "B53 MMAP connected switch driver"
-+      depends on B53
-+      help
-+        Select to enable support for memory-mapped switches like the BCM63XX
-+        integrated switches.
-+
-+config B53_SRAB_DRIVER
-+      tristate "B53 SRAB connected switch driver"
-+      depends on B53
-+      help
-+        Select to enable support for memory-mapped Switch Register Access
-+        Bridge Registers (SRAB) like it is found on the BCM53010
-+
-+config B53_PHY_FIXUP
-+      bool
-diff --git a/drivers/net/phy/b53/Makefile b/drivers/net/phy/b53/Makefile
-new file mode 100644
-index 0000000..7cc39c7
---- /dev/null
-+++ b/drivers/net/phy/b53/Makefile
-@@ -0,0 +1,10 @@
-+obj-$(CONFIG_B53)             += b53_common.o
-+
-+obj-$(CONFIG_B53_PHY_FIXUP)   += b53_phy_fixup.o
-+
-+obj-$(CONFIG_B53_MMAP_DRIVER) += b53_mmap.o
-+obj-$(CONFIG_B53_SRAB_DRIVER) += b53_srab.o
-+obj-$(CONFIG_B53_PHY_DRIVER)  += b53_mdio.o
-+obj-$(CONFIG_B53_SPI_DRIVER)  += b53_spi.o
-+
-+ccflags-y                     += -Werror
-diff --git a/drivers/net/phy/b53/b53_common.c b/drivers/net/phy/b53/b53_common.c
-new file mode 100644
-index 0000000..b82bc93
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_common.c
-@@ -0,0 +1,1428 @@
-+/*
-+ * B53 switch driver main logic
-+ *
-+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/delay.h>
-+#include <linux/export.h>
-+#include <linux/gpio.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/switch.h>
-+#include <linux/platform_data/b53.h>
-+
-+#include "b53_regs.h"
-+#include "b53_priv.h"
-+
-+/* buffer size needed for displaying all MIBs with max'd values */
-+#define B53_BUF_SIZE  1188
-+
-+struct b53_mib_desc {
-+      u8 size;
-+      u8 offset;
-+      const char *name;
-+};
-+
-+
-+/* BCM5365 MIB counters */
-+static const struct b53_mib_desc b53_mibs_65[] = {
-+      { 8, 0x00, "TxOctets" },
-+      { 4, 0x08, "TxDropPkts" },
-+      { 4, 0x10, "TxBroadcastPkts" },
-+      { 4, 0x14, "TxMulticastPkts" },
-+      { 4, 0x18, "TxUnicastPkts" },
-+      { 4, 0x1c, "TxCollisions" },
-+      { 4, 0x20, "TxSingleCollision" },
-+      { 4, 0x24, "TxMultipleCollision" },
-+      { 4, 0x28, "TxDeferredTransmit" },
-+      { 4, 0x2c, "TxLateCollision" },
-+      { 4, 0x30, "TxExcessiveCollision" },
-+      { 4, 0x38, "TxPausePkts" },
-+      { 8, 0x44, "RxOctets" },
-+      { 4, 0x4c, "RxUndersizePkts" },
-+      { 4, 0x50, "RxPausePkts" },
-+      { 4, 0x54, "Pkts64Octets" },
-+      { 4, 0x58, "Pkts65to127Octets" },
-+      { 4, 0x5c, "Pkts128to255Octets" },
-+      { 4, 0x60, "Pkts256to511Octets" },
-+      { 4, 0x64, "Pkts512to1023Octets" },
-+      { 4, 0x68, "Pkts1024to1522Octets" },
-+      { 4, 0x6c, "RxOversizePkts" },
-+      { 4, 0x70, "RxJabbers" },
-+      { 4, 0x74, "RxAlignmentErrors" },
-+      { 4, 0x78, "RxFCSErrors" },
-+      { 8, 0x7c, "RxGoodOctets" },
-+      { 4, 0x84, "RxDropPkts" },
-+      { 4, 0x88, "RxUnicastPkts" },
-+      { 4, 0x8c, "RxMulticastPkts" },
-+      { 4, 0x90, "RxBroadcastPkts" },
-+      { 4, 0x94, "RxSAChanges" },
-+      { 4, 0x98, "RxFragments" },
-+      { },
-+};
-+
-+/* BCM63xx MIB counters */
-+static const struct b53_mib_desc b53_mibs_63xx[] = {
-+      { 8, 0x00, "TxOctets" },
-+      { 4, 0x08, "TxDropPkts" },
-+      { 4, 0x0c, "TxQoSPkts" },
-+      { 4, 0x10, "TxBroadcastPkts" },
-+      { 4, 0x14, "TxMulticastPkts" },
-+      { 4, 0x18, "TxUnicastPkts" },
-+      { 4, 0x1c, "TxCollisions" },
-+      { 4, 0x20, "TxSingleCollision" },
-+      { 4, 0x24, "TxMultipleCollision" },
-+      { 4, 0x28, "TxDeferredTransmit" },
-+      { 4, 0x2c, "TxLateCollision" },
-+      { 4, 0x30, "TxExcessiveCollision" },
-+      { 4, 0x38, "TxPausePkts" },
-+      { 8, 0x3c, "TxQoSOctets" },
-+      { 8, 0x44, "RxOctets" },
-+      { 4, 0x4c, "RxUndersizePkts" },
-+      { 4, 0x50, "RxPausePkts" },
-+      { 4, 0x54, "Pkts64Octets" },
-+      { 4, 0x58, "Pkts65to127Octets" },
-+      { 4, 0x5c, "Pkts128to255Octets" },
-+      { 4, 0x60, "Pkts256to511Octets" },
-+      { 4, 0x64, "Pkts512to1023Octets" },
-+      { 4, 0x68, "Pkts1024to1522Octets" },
-+      { 4, 0x6c, "RxOversizePkts" },
-+      { 4, 0x70, "RxJabbers" },
-+      { 4, 0x74, "RxAlignmentErrors" },
-+      { 4, 0x78, "RxFCSErrors" },
-+      { 8, 0x7c, "RxGoodOctets" },
-+      { 4, 0x84, "RxDropPkts" },
-+      { 4, 0x88, "RxUnicastPkts" },
-+      { 4, 0x8c, "RxMulticastPkts" },
-+      { 4, 0x90, "RxBroadcastPkts" },
-+      { 4, 0x94, "RxSAChanges" },
-+      { 4, 0x98, "RxFragments" },
-+      { 4, 0xa0, "RxSymbolErrors" },
-+      { 4, 0xa4, "RxQoSPkts" },
-+      { 8, 0xa8, "RxQoSOctets" },
-+      { 4, 0xb0, "Pkts1523to2047Octets" },
-+      { 4, 0xb4, "Pkts2048to4095Octets" },
-+      { 4, 0xb8, "Pkts4096to8191Octets" },
-+      { 4, 0xbc, "Pkts8192to9728Octets" },
-+      { 4, 0xc0, "RxDiscarded" },
-+      { }
-+};
-+
-+/* MIB counters */
-+static const struct b53_mib_desc b53_mibs[] = {
-+      { 8, 0x00, "TxOctets" },
-+      { 4, 0x08, "TxDropPkts" },
-+      { 4, 0x10, "TxBroadcastPkts" },
-+      { 4, 0x14, "TxMulticastPkts" },
-+      { 4, 0x18, "TxUnicastPkts" },
-+      { 4, 0x1c, "TxCollisions" },
-+      { 4, 0x20, "TxSingleCollision" },
-+      { 4, 0x24, "TxMultipleCollision" },
-+      { 4, 0x28, "TxDeferredTransmit" },
-+      { 4, 0x2c, "TxLateCollision" },
-+      { 4, 0x30, "TxExcessiveCollision" },
-+      { 4, 0x38, "TxPausePkts" },
-+      { 8, 0x50, "RxOctets" },
-+      { 4, 0x58, "RxUndersizePkts" },
-+      { 4, 0x5c, "RxPausePkts" },
-+      { 4, 0x60, "Pkts64Octets" },
-+      { 4, 0x64, "Pkts65to127Octets" },
-+      { 4, 0x68, "Pkts128to255Octets" },
-+      { 4, 0x6c, "Pkts256to511Octets" },
-+      { 4, 0x70, "Pkts512to1023Octets" },
-+      { 4, 0x74, "Pkts1024to1522Octets" },
-+      { 4, 0x78, "RxOversizePkts" },
-+      { 4, 0x7c, "RxJabbers" },
-+      { 4, 0x80, "RxAlignmentErrors" },
-+      { 4, 0x84, "RxFCSErrors" },
-+      { 8, 0x88, "RxGoodOctets" },
-+      { 4, 0x90, "RxDropPkts" },
-+      { 4, 0x94, "RxUnicastPkts" },
-+      { 4, 0x98, "RxMulticastPkts" },
-+      { 4, 0x9c, "RxBroadcastPkts" },
-+      { 4, 0xa0, "RxSAChanges" },
-+      { 4, 0xa4, "RxFragments" },
-+      { 4, 0xa8, "RxJumboPkts" },
-+      { 4, 0xac, "RxSymbolErrors" },
-+      { 4, 0xc0, "RxDiscarded" },
-+      { }
-+};
-+
-+static int b53_do_vlan_op(struct b53_device *dev, u8 op)
-+{
-+      unsigned int i;
-+
-+      b53_write8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], VTA_START_CMD | op);
-+
-+      for (i = 0; i < 10; i++) {
-+              u8 vta;
-+
-+              b53_read8(dev, B53_ARLIO_PAGE, dev->vta_regs[0], &vta);
-+              if (!(vta & VTA_START_CMD))
-+                      return 0;
-+
-+              usleep_range(100, 200);
-+      }
-+
-+      return -EIO;
-+}
-+
-+static void b53_set_vlan_entry(struct b53_device *dev, u16 vid, u16 members,
-+                             u16 untag)
-+{
-+      if (is5325(dev)) {
-+              u32 entry = 0;
-+
-+              if (members) {
-+                      entry = ((untag & VA_UNTAG_MASK_25) << VA_UNTAG_S_25) |
-+                              members;
-+                      if (dev->core_rev >= 3)
-+                              entry |= VA_VALID_25_R4 | vid << VA_VID_HIGH_S;
-+                      else
-+                              entry |= VA_VALID_25;
-+              }
-+
-+              b53_write32(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_25, entry);
-+              b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, vid |
-+                          VTA_RW_STATE_WR | VTA_RW_OP_EN);
-+      } else if (is5365(dev)) {
-+              u16 entry = 0;
-+
-+              if (members)
-+                      entry = ((untag & VA_UNTAG_MASK_65) << VA_UNTAG_S_65) |
-+                              members | VA_VALID_65;
-+
-+              b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_WRITE_65, entry);
-+              b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_65, vid |
-+                          VTA_RW_STATE_WR | VTA_RW_OP_EN);
-+      } else {
-+              b53_write16(dev, B53_ARLIO_PAGE, dev->vta_regs[1], vid);
-+              b53_write32(dev, B53_ARLIO_PAGE, dev->vta_regs[2],
-+                          (untag << VTE_UNTAG_S) | members);
-+
-+              b53_do_vlan_op(dev, VTA_CMD_WRITE);
-+      }
-+}
-+
-+void b53_set_forwarding(struct b53_device *dev, int enable)
-+{
-+      u8 mgmt;
-+
-+      b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
-+
-+      if (enable)
-+              mgmt |= SM_SW_FWD_EN;
-+      else
-+              mgmt &= ~SM_SW_FWD_EN;
-+
-+      b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
-+}
-+
-+static void b53_enable_vlan(struct b53_device *dev, int enable)
-+{
-+      u8 mgmt, vc0, vc1, vc4 = 0, vc5;
-+
-+      b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
-+      b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, &vc0);
-+      b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, &vc1);
-+
-+      if (is5325(dev) || is5365(dev)) {
-+              b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
-+              b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, &vc5);
-+      } else if (is63xx(dev)) {
-+              b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, &vc4);
-+              b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, &vc5);
-+      } else {
-+              b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, &vc4);
-+              b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, &vc5);
-+      }
-+
-+      mgmt &= ~SM_SW_FWD_MODE;
-+
-+      if (enable) {
-+              vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
-+              vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
-+              vc4 &= ~VC4_ING_VID_CHECK_MASK;
-+              vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
-+              vc5 |= VC5_DROP_VTABLE_MISS;
-+
-+              if (is5325(dev))
-+                      vc0 &= ~VC0_RESERVED_1;
-+
-+              if (is5325(dev) || is5365(dev))
-+                      vc1 |= VC1_RX_MCST_TAG_EN;
-+
-+              if (!is5325(dev) && !is5365(dev)) {
-+                      if (dev->allow_vid_4095)
-+                              vc5 |= VC5_VID_FFF_EN;
-+                      else
-+                              vc5 &= ~VC5_VID_FFF_EN;
-+              }
-+      } else {
-+              vc0 &= ~(VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID);
-+              vc1 &= ~(VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN);
-+              vc4 &= ~VC4_ING_VID_CHECK_MASK;
-+              vc5 &= ~VC5_DROP_VTABLE_MISS;
-+
-+              if (is5325(dev) || is5365(dev))
-+                      vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S;
-+              else
-+                      vc4 |= VC4_ING_VID_VIO_TO_IMP << VC4_ING_VID_CHECK_S;
-+
-+              if (is5325(dev) || is5365(dev))
-+                      vc1 &= ~VC1_RX_MCST_TAG_EN;
-+
-+              if (!is5325(dev) && !is5365(dev))
-+                      vc5 &= ~VC5_VID_FFF_EN;
-+      }
-+
-+      b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL0, vc0);
-+      b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL1, vc1);
-+
-+      if (is5325(dev) || is5365(dev)) {
-+              /* enable the high 8 bit vid check on 5325 */
-+              if (is5325(dev) && enable)
-+                      b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3,
-+                                 VC3_HIGH_8BIT_EN);
-+              else
-+                      b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
-+
-+              b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, vc4);
-+              b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_25, vc5);
-+      } else if (is63xx(dev)) {
-+              b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3_63XX, 0);
-+              b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_63XX, vc4);
-+              b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5_63XX, vc5);
-+      } else {
-+              b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_CTRL3, 0);
-+              b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4, vc4);
-+              b53_write8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL5, vc5);
-+      }
-+
-+      b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
-+}
-+
-+static int b53_set_jumbo(struct b53_device *dev, int enable, int allow_10_100)
-+{
-+      u32 port_mask = 0;
-+      u16 max_size = JMS_MIN_SIZE;
-+
-+      if (is5325(dev) || is5365(dev))
-+              return -EINVAL;
-+
-+      if (enable) {
-+              port_mask = dev->enabled_ports;
-+              max_size = JMS_MAX_SIZE;
-+              if (allow_10_100)
-+                      port_mask |= JPM_10_100_JUMBO_EN;
-+      }
-+
-+      b53_write32(dev, B53_JUMBO_PAGE, dev->jumbo_pm_reg, port_mask);
-+      return b53_write16(dev, B53_JUMBO_PAGE, dev->jumbo_size_reg, max_size);
-+}
-+
-+static int b53_flush_arl(struct b53_device *dev)
-+{
-+      unsigned int i;
-+
-+      b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
-+                 FAST_AGE_DONE | FAST_AGE_DYNAMIC | FAST_AGE_STATIC);
-+
-+      for (i = 0; i < 10; i++) {
-+              u8 fast_age_ctrl;
-+
-+              b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL,
-+                        &fast_age_ctrl);
-+
-+              if (!(fast_age_ctrl & FAST_AGE_DONE))
-+                      return 0;
-+
-+              mdelay(1);
-+      }
-+
-+      pr_warn("time out while flushing ARL\n");
-+
-+      return -EINVAL;
-+}
-+
-+static void b53_enable_ports(struct b53_device *dev)
-+{
-+      unsigned i;
-+
-+      b53_for_each_port(dev, i) {
-+              u8 port_ctrl;
-+              u16 pvlan_mask;
-+
-+              /*
-+               * prevent leaking packets between wan and lan in unmanaged
-+               * mode through port vlans.
-+               */
-+              if (dev->enable_vlan || is_cpu_port(dev, i))
-+                      pvlan_mask = 0x1ff;
-+              else if (is531x5(dev) || is5301x(dev))
-+                      /* BCM53115 may use a different port as cpu port */
-+                      pvlan_mask = BIT(dev->sw_dev.cpu_port);
-+              else
-+                      pvlan_mask = BIT(B53_CPU_PORT);
-+
-+              /* BCM5325 CPU port is at 8 */
-+              if ((is5325(dev) || is5365(dev)) && i == B53_CPU_PORT_25)
-+                      i = B53_CPU_PORT;
-+
-+              if (dev->chip_id == BCM5398_DEVICE_ID && (i == 6 || i == 7))
-+                      /* disable unused ports 6 & 7 */
-+                      port_ctrl = PORT_CTRL_RX_DISABLE | PORT_CTRL_TX_DISABLE;
-+              else if (i == B53_CPU_PORT)
-+                      port_ctrl = PORT_CTRL_RX_BCST_EN |
-+                                  PORT_CTRL_RX_MCST_EN |
-+                                  PORT_CTRL_RX_UCST_EN;
-+              else
-+                      port_ctrl = 0;
-+
-+              b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i),
-+                          pvlan_mask);
-+
-+              /* port state is handled by bcm63xx_enet driver */
-+              if (!is63xx(dev) && !(is5301x(dev) && i == 6))
-+                      b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(i),
-+                                 port_ctrl);
-+      }
-+}
-+
-+static void b53_enable_mib(struct b53_device *dev)
-+{
-+      u8 gc;
-+
-+      b53_read8(dev, B53_CTRL_PAGE, B53_GLOBAL_CONFIG, &gc);
-+
-+      gc &= ~(GC_RESET_MIB | GC_MIB_AC_EN);
-+
-+      b53_write8(dev, B53_CTRL_PAGE, B53_GLOBAL_CONFIG, gc);
-+}
-+
-+static int b53_apply(struct b53_device *dev)
-+{
-+      int i;
-+
-+      /* clear all vlan entries */
-+      if (is5325(dev) || is5365(dev)) {
-+              for (i = 1; i < dev->sw_dev.vlans; i++)
-+                      b53_set_vlan_entry(dev, i, 0, 0);
-+      } else {
-+              b53_do_vlan_op(dev, VTA_CMD_CLEAR);
-+      }
-+
-+      b53_enable_vlan(dev, dev->enable_vlan);
-+
-+      /* fill VLAN table */
-+      if (dev->enable_vlan) {
-+              for (i = 0; i < dev->sw_dev.vlans; i++) {
-+                      struct b53_vlan *vlan = &dev->vlans[i];
-+
-+                      if (!vlan->members)
-+                              continue;
-+
-+                      b53_set_vlan_entry(dev, i, vlan->members, vlan->untag);
-+              }
-+
-+              b53_for_each_port(dev, i)
-+                      b53_write16(dev, B53_VLAN_PAGE,
-+                                  B53_VLAN_PORT_DEF_TAG(i),
-+                                  dev->ports[i].pvid);
-+      } else {
-+              b53_for_each_port(dev, i)
-+                      b53_write16(dev, B53_VLAN_PAGE,
-+                                  B53_VLAN_PORT_DEF_TAG(i), 1);
-+
-+      }
-+
-+      b53_enable_ports(dev);
-+
-+      if (!is5325(dev) && !is5365(dev))
-+              b53_set_jumbo(dev, dev->enable_jumbo, 1);
-+
-+      return 0;
-+}
-+
-+static void b53_switch_reset_gpio(struct b53_device *dev)
-+{
-+      int gpio = dev->reset_gpio;
-+
-+      if (gpio < 0)
-+              return;
-+
-+      /*
-+       * Reset sequence: RESET low(50ms)->high(20ms)
-+       */
-+      gpio_set_value(gpio, 0);
-+      mdelay(50);
-+
-+      gpio_set_value(gpio, 1);
-+      mdelay(20);
-+
-+      dev->current_page = 0xff;
-+}
-+
-+static int b53_switch_reset(struct b53_device *dev)
-+{
-+      u8 mgmt;
-+
-+      b53_switch_reset_gpio(dev);
-+
-+      if (is539x(dev)) {
-+              b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x83);
-+              b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, 0x00);
-+      }
-+
-+      b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
-+
-+      if (!(mgmt & SM_SW_FWD_EN)) {
-+              mgmt &= ~SM_SW_FWD_MODE;
-+              mgmt |= SM_SW_FWD_EN;
-+
-+              b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
-+              b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt);
-+
-+              if (!(mgmt & SM_SW_FWD_EN)) {
-+                      pr_err("Failed to enable switch!\n");
-+                      return -EINVAL;
-+              }
-+      }
-+
-+      /* enable all ports */
-+      b53_enable_ports(dev);
-+
-+      /* configure MII port if necessary */
-+      if (is5325(dev)) {
-+              u8 mii_port_override;
-+
-+              b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
-+                        &mii_port_override);
-+              /* reverse mii needs to be enabled */
-+              if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
-+                      b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
-+                                 mii_port_override | PORT_OVERRIDE_RV_MII_25);
-+                      b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
-+                                &mii_port_override);
-+
-+                      if (!(mii_port_override & PORT_OVERRIDE_RV_MII_25)) {
-+                              pr_err("Failed to enable reverse MII mode\n");
-+                              return -EINVAL;
-+                      }
-+              }
-+      } else if ((is531x5(dev) || is5301x(dev)) && dev->sw_dev.cpu_port == B53_CPU_PORT) {
-+              u8 mii_port_override;
-+
-+              b53_read8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
-+                        &mii_port_override);
-+              b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL,
-+                         mii_port_override | PORT_OVERRIDE_EN |
-+                         PORT_OVERRIDE_LINK);
-+      }
-+
-+      b53_enable_mib(dev);
-+
-+      return b53_flush_arl(dev);
-+}
-+
-+/*
-+ * Swconfig glue functions
-+ */
-+
-+static int b53_global_get_vlan_enable(struct switch_dev *dev,
-+                                    const struct switch_attr *attr,
-+                                    struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      val->value.i = priv->enable_vlan;
-+
-+      return 0;
-+}
-+
-+static int b53_global_set_vlan_enable(struct switch_dev *dev,
-+                                    const struct switch_attr *attr,
-+                                    struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      priv->enable_vlan = val->value.i;
-+
-+      return 0;
-+}
-+
-+static int b53_global_get_jumbo_enable(struct switch_dev *dev,
-+                                     const struct switch_attr *attr,
-+                                     struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      val->value.i = priv->enable_jumbo;
-+
-+      return 0;
-+}
-+
-+static int b53_global_set_jumbo_enable(struct switch_dev *dev,
-+                                     const struct switch_attr *attr,
-+                                     struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      priv->enable_jumbo = val->value.i;
-+
-+      return 0;
-+}
-+
-+static int b53_global_get_4095_enable(struct switch_dev *dev,
-+                                    const struct switch_attr *attr,
-+                                    struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      val->value.i = priv->allow_vid_4095;
-+
-+      return 0;
-+}
-+
-+static int b53_global_set_4095_enable(struct switch_dev *dev,
-+                                    const struct switch_attr *attr,
-+                                    struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      priv->allow_vid_4095 = val->value.i;
-+
-+      return 0;
-+}
-+
-+static int b53_global_get_ports(struct switch_dev *dev,
-+                              const struct switch_attr *attr,
-+                              struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      val->len = snprintf(priv->buf, B53_BUF_SIZE, "0x%04x",
-+                          priv->enabled_ports);
-+      val->value.s = priv->buf;
-+
-+      return 0;
-+}
-+
-+static int b53_port_get_pvid(struct switch_dev *dev, int port, int *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      *val = priv->ports[port].pvid;
-+
-+      return 0;
-+}
-+
-+static int b53_port_set_pvid(struct switch_dev *dev, int port, int val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      if (val > 15 && is5325(priv))
-+              return -EINVAL;
-+      if (val == 4095 && !priv->allow_vid_4095)
-+              return -EINVAL;
-+
-+      priv->ports[port].pvid = val;
-+
-+      return 0;
-+}
-+
-+static int b53_vlan_get_ports(struct switch_dev *dev, struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+      struct switch_port *port = &val->value.ports[0];
-+      struct b53_vlan *vlan = &priv->vlans[val->port_vlan];
-+      int i;
-+
-+      val->len = 0;
-+
-+      if (!vlan->members)
-+              return 0;
-+
-+      for (i = 0; i < dev->ports; i++) {
-+              if (!(vlan->members & BIT(i)))
-+                      continue;
-+
-+
-+              if (!(vlan->untag & BIT(i)))
-+                      port->flags = BIT(SWITCH_PORT_FLAG_TAGGED);
-+              else
-+                      port->flags = 0;
-+
-+              port->id = i;
-+              val->len++;
-+              port++;
-+      }
-+
-+      return 0;
-+}
-+
-+static int b53_vlan_set_ports(struct switch_dev *dev, struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+      struct switch_port *port;
-+      struct b53_vlan *vlan = &priv->vlans[val->port_vlan];
-+      int i;
-+
-+      /* only BCM5325 and BCM5365 supports VID 0 */
-+      if (val->port_vlan == 0 && !is5325(priv) && !is5365(priv))
-+              return -EINVAL;
-+
-+      /* VLAN 4095 needs special handling */
-+      if (val->port_vlan == 4095 && !priv->allow_vid_4095)
-+              return -EINVAL;
-+
-+      port = &val->value.ports[0];
-+      vlan->members = 0;
-+      vlan->untag = 0;
-+      for (i = 0; i < val->len; i++, port++) {
-+              vlan->members |= BIT(port->id);
-+
-+              if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) {
-+                      vlan->untag |= BIT(port->id);
-+                      priv->ports[port->id].pvid = val->port_vlan;
-+              };
-+      }
-+
-+      /* ignore disabled ports */
-+      vlan->members &= priv->enabled_ports;
-+      vlan->untag &= priv->enabled_ports;
-+
-+      return 0;
-+}
-+
-+static int b53_port_get_link(struct switch_dev *dev, int port,
-+                           struct switch_port_link *link)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      if (is_cpu_port(priv, port)) {
-+              link->link = 1;
-+              link->duplex = 1;
-+              link->speed = is5325(priv) || is5365(priv) ?
-+                              SWITCH_PORT_SPEED_100 : SWITCH_PORT_SPEED_1000;
-+              link->aneg = 0;
-+      } else if (priv->enabled_ports & BIT(port)) {
-+              u32 speed;
-+              u16 lnk, duplex;
-+
-+              b53_read16(priv, B53_STAT_PAGE, B53_LINK_STAT, &lnk);
-+              b53_read16(priv, B53_STAT_PAGE, priv->duplex_reg, &duplex);
-+
-+              lnk = (lnk >> port) & 1;
-+              duplex = (duplex >> port) & 1;
-+
-+              if (is5325(priv) || is5365(priv)) {
-+                      u16 tmp;
-+
-+                      b53_read16(priv, B53_STAT_PAGE, B53_SPEED_STAT, &tmp);
-+                      speed = SPEED_PORT_FE(tmp, port);
-+              } else {
-+                      b53_read32(priv, B53_STAT_PAGE, B53_SPEED_STAT, &speed);
-+                      speed = SPEED_PORT_GE(speed, port);
-+              }
-+
-+              link->link = lnk;
-+              if (lnk) {
-+                      link->duplex = duplex;
-+                      switch (speed) {
-+                      case SPEED_STAT_10M:
-+                              link->speed = SWITCH_PORT_SPEED_10;
-+                              break;
-+                      case SPEED_STAT_100M:
-+                              link->speed = SWITCH_PORT_SPEED_100;
-+                              break;
-+                      case SPEED_STAT_1000M:
-+                              link->speed = SWITCH_PORT_SPEED_1000;
-+                              break;
-+                      }
-+              }
-+
-+              link->aneg = 1;
-+      } else {
-+              link->link = 0;
-+      }
-+
-+      return 0;
-+
-+}
-+
-+static int b53_global_reset_switch(struct switch_dev *dev)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      /* reset vlans */
-+      priv->enable_vlan = 0;
-+      priv->enable_jumbo = 0;
-+      priv->allow_vid_4095 = 0;
-+
-+      memset(priv->vlans, 0, sizeof(priv->vlans) * dev->vlans);
-+      memset(priv->ports, 0, sizeof(priv->ports) * dev->ports);
-+
-+      return b53_switch_reset(priv);
-+}
-+
-+static int b53_global_apply_config(struct switch_dev *dev)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+
-+      /* disable switching */
-+      b53_set_forwarding(priv, 0);
-+
-+      b53_apply(priv);
-+
-+      /* enable switching */
-+      b53_set_forwarding(priv, 1);
-+
-+      return 0;
-+}
-+
-+
-+static int b53_global_reset_mib(struct switch_dev *dev,
-+                              const struct switch_attr *attr,
-+                              struct switch_val *val)
-+{
-+      struct b53_device *priv = sw_to_b53(dev);
-+      u8 gc;
-+
-+      b53_read8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, &gc);
-+
-+      b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc | GC_RESET_MIB);
-+      mdelay(1);
-+      b53_write8(priv, B53_MGMT_PAGE, B53_GLOBAL_CONFIG, gc & ~GC_RESET_MIB);
-+      mdelay(1);
-+
-+      return 0;
-+}
-+
-+static int b53_port_get_mib(struct switch_dev *sw_dev,
-+                          const struct switch_attr *attr,
-+                          struct switch_val *val)
-+{
-+      struct b53_device *dev = sw_to_b53(sw_dev);
-+      const struct b53_mib_desc *mibs;
-+      int port = val->port_vlan;
-+      int len = 0;
-+
-+      if (!(BIT(port) & dev->enabled_ports))
-+              return -1;
-+
-+      if (is5365(dev)) {
-+              if (port == 5)
-+                      port = 8;
-+
-+              mibs = b53_mibs_65;
-+      } else if (is63xx(dev)) {
-+              mibs = b53_mibs_63xx;
-+      } else {
-+              mibs = b53_mibs;
-+      }
-+
-+      dev->buf[0] = 0;
-+
-+      for (; mibs->size > 0; mibs++) {
-+              u64 val;
-+
-+              if (mibs->size == 8) {
-+                      b53_read64(dev, B53_MIB_PAGE(port), mibs->offset, &val);
-+              } else {
-+                      u32 val32;
-+
-+                      b53_read32(dev, B53_MIB_PAGE(port), mibs->offset,
-+                                 &val32);
-+                      val = val32;
-+              }
-+
-+              len += snprintf(dev->buf + len, B53_BUF_SIZE - len,
-+                              "%-20s: %llu\n", mibs->name, val);
-+      }
-+
-+      val->len = len;
-+      val->value.s = dev->buf;
-+
-+      return 0;
-+}
-+
-+static struct switch_attr b53_global_ops_25[] = {
-+      {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "enable_vlan",
-+              .description = "Enable VLAN mode",
-+              .set = b53_global_set_vlan_enable,
-+              .get = b53_global_get_vlan_enable,
-+              .max = 1,
-+      },
-+      {
-+              .type = SWITCH_TYPE_STRING,
-+              .name = "ports",
-+              .description = "Available ports (as bitmask)",
-+              .get = b53_global_get_ports,
-+      },
-+};
-+
-+static struct switch_attr b53_global_ops_65[] = {
-+      {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "enable_vlan",
-+              .description = "Enable VLAN mode",
-+              .set = b53_global_set_vlan_enable,
-+              .get = b53_global_get_vlan_enable,
-+              .max = 1,
-+      },
-+      {
-+              .type = SWITCH_TYPE_STRING,
-+              .name = "ports",
-+              .description = "Available ports (as bitmask)",
-+              .get = b53_global_get_ports,
-+      },
-+      {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "reset_mib",
-+              .description = "Reset MIB counters",
-+              .set = b53_global_reset_mib,
-+      },
-+};
-+
-+static struct switch_attr b53_global_ops[] = {
-+      {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "enable_vlan",
-+              .description = "Enable VLAN mode",
-+              .set = b53_global_set_vlan_enable,
-+              .get = b53_global_get_vlan_enable,
-+              .max = 1,
-+      },
-+      {
-+              .type = SWITCH_TYPE_STRING,
-+              .name = "ports",
-+              .description = "Available Ports (as bitmask)",
-+              .get = b53_global_get_ports,
-+      },
-+      {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "reset_mib",
-+              .description = "Reset MIB counters",
-+              .set = b53_global_reset_mib,
-+      },
-+      {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "enable_jumbo",
-+              .description = "Enable Jumbo Frames",
-+              .set = b53_global_set_jumbo_enable,
-+              .get = b53_global_get_jumbo_enable,
-+              .max = 1,
-+      },
-+      {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "allow_vid_4095",
-+              .description = "Allow VID 4095",
-+              .set = b53_global_set_4095_enable,
-+              .get = b53_global_get_4095_enable,
-+              .max = 1,
-+      },
-+};
-+
-+static struct switch_attr b53_port_ops[] = {
-+      {
-+              .type = SWITCH_TYPE_STRING,
-+              .name = "mib",
-+              .description = "Get port's MIB counters",
-+              .get = b53_port_get_mib,
-+      },
-+};
-+
-+static struct switch_attr b53_no_ops[] = {
-+};
-+
-+static const struct switch_dev_ops b53_switch_ops_25 = {
-+      .attr_global = {
-+              .attr = b53_global_ops_25,
-+              .n_attr = ARRAY_SIZE(b53_global_ops_25),
-+      },
-+      .attr_port = {
-+              .attr = b53_no_ops,
-+              .n_attr = ARRAY_SIZE(b53_no_ops),
-+      },
-+      .attr_vlan = {
-+              .attr = b53_no_ops,
-+              .n_attr = ARRAY_SIZE(b53_no_ops),
-+      },
-+
-+      .get_vlan_ports = b53_vlan_get_ports,
-+      .set_vlan_ports = b53_vlan_set_ports,
-+      .get_port_pvid = b53_port_get_pvid,
-+      .set_port_pvid = b53_port_set_pvid,
-+      .apply_config = b53_global_apply_config,
-+      .reset_switch = b53_global_reset_switch,
-+      .get_port_link = b53_port_get_link,
-+};
-+
-+static const struct switch_dev_ops b53_switch_ops_65 = {
-+      .attr_global = {
-+              .attr = b53_global_ops_65,
-+              .n_attr = ARRAY_SIZE(b53_global_ops_65),
-+      },
-+      .attr_port = {
-+              .attr = b53_port_ops,
-+              .n_attr = ARRAY_SIZE(b53_port_ops),
-+      },
-+      .attr_vlan = {
-+              .attr = b53_no_ops,
-+              .n_attr = ARRAY_SIZE(b53_no_ops),
-+      },
-+
-+      .get_vlan_ports = b53_vlan_get_ports,
-+      .set_vlan_ports = b53_vlan_set_ports,
-+      .get_port_pvid = b53_port_get_pvid,
-+      .set_port_pvid = b53_port_set_pvid,
-+      .apply_config = b53_global_apply_config,
-+      .reset_switch = b53_global_reset_switch,
-+      .get_port_link = b53_port_get_link,
-+};
-+
-+static const struct switch_dev_ops b53_switch_ops = {
-+      .attr_global = {
-+              .attr = b53_global_ops,
-+              .n_attr = ARRAY_SIZE(b53_global_ops),
-+      },
-+      .attr_port = {
-+              .attr = b53_port_ops,
-+              .n_attr = ARRAY_SIZE(b53_port_ops),
-+      },
-+      .attr_vlan = {
-+              .attr = b53_no_ops,
-+              .n_attr = ARRAY_SIZE(b53_no_ops),
-+      },
-+
-+      .get_vlan_ports = b53_vlan_get_ports,
-+      .set_vlan_ports = b53_vlan_set_ports,
-+      .get_port_pvid = b53_port_get_pvid,
-+      .set_port_pvid = b53_port_set_pvid,
-+      .apply_config = b53_global_apply_config,
-+      .reset_switch = b53_global_reset_switch,
-+      .get_port_link = b53_port_get_link,
-+};
-+
-+struct b53_chip_data {
-+      u32 chip_id;
-+      const char *dev_name;
-+      const char *alias;
-+      u16 vlans;
-+      u16 enabled_ports;
-+      u8 cpu_port;
-+      u8 vta_regs[3];
-+      u8 duplex_reg;
-+      u8 jumbo_pm_reg;
-+      u8 jumbo_size_reg;
-+      const struct switch_dev_ops *sw_ops;
-+};
-+
-+#define B53_VTA_REGS  \
-+      { B53_VT_ACCESS, B53_VT_INDEX, B53_VT_ENTRY }
-+#define B53_VTA_REGS_9798 \
-+      { B53_VT_ACCESS_9798, B53_VT_INDEX_9798, B53_VT_ENTRY_9798 }
-+#define B53_VTA_REGS_63XX \
-+      { B53_VT_ACCESS_63XX, B53_VT_INDEX_63XX, B53_VT_ENTRY_63XX }
-+
-+static const struct b53_chip_data b53_switch_chips[] = {
-+      {
-+              .chip_id = BCM5325_DEVICE_ID,
-+              .dev_name = "BCM5325",
-+              .alias = "bcm5325",
-+              .vlans = 16,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT_25,
-+              .duplex_reg = B53_DUPLEX_STAT_FE,
-+              .sw_ops = &b53_switch_ops_25,
-+      },
-+      {
-+              .chip_id = BCM5365_DEVICE_ID,
-+              .dev_name = "BCM5365",
-+              .alias = "bcm5365",
-+              .vlans = 256,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT_25,
-+              .duplex_reg = B53_DUPLEX_STAT_FE,
-+              .sw_ops = &b53_switch_ops_65,
-+      },
-+      {
-+              .chip_id = BCM5395_DEVICE_ID,
-+              .dev_name = "BCM5395",
-+              .alias = "bcm5395",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT,
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM5397_DEVICE_ID,
-+              .dev_name = "BCM5397",
-+              .alias = "bcm5397",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT,
-+              .vta_regs = B53_VTA_REGS_9798,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM5398_DEVICE_ID,
-+              .dev_name = "BCM5398",
-+              .alias = "bcm5398",
-+              .vlans = 4096,
-+              .enabled_ports = 0x7f,
-+              .cpu_port = B53_CPU_PORT,
-+              .vta_regs = B53_VTA_REGS_9798,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53115_DEVICE_ID,
-+              .dev_name = "BCM53115",
-+              .alias = "bcm53115",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .vta_regs = B53_VTA_REGS,
-+              .cpu_port = B53_CPU_PORT,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53125_DEVICE_ID,
-+              .dev_name = "BCM53125",
-+              .alias = "bcm53125",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT,
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53128_DEVICE_ID,
-+              .dev_name = "BCM53128",
-+              .alias = "bcm53128",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1ff,
-+              .cpu_port = B53_CPU_PORT,
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM63XX_DEVICE_ID,
-+              .dev_name = "BCM63xx",
-+              .alias = "bcm63xx",
-+              .vlans = 4096,
-+              .enabled_ports = 0, /* pdata must provide them */
-+              .cpu_port = B53_CPU_PORT,
-+              .vta_regs = B53_VTA_REGS_63XX,
-+              .duplex_reg = B53_DUPLEX_STAT_63XX,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53010_DEVICE_ID,
-+              .dev_name = "BCM53010",
-+              .alias = "bcm53011",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT_25, // TODO: auto detect
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53011_DEVICE_ID,
-+              .dev_name = "BCM53011",
-+              .alias = "bcm53011",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT_25, // TODO: auto detect
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53012_DEVICE_ID,
-+              .dev_name = "BCM53012",
-+              .alias = "bcm53011",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT_25, // TODO: auto detect
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53018_DEVICE_ID,
-+              .dev_name = "BCM53018",
-+              .alias = "bcm53018",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT_25, // TODO: auto detect
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+      {
-+              .chip_id = BCM53019_DEVICE_ID,
-+              .dev_name = "BCM53019",
-+              .alias = "bcm53019",
-+              .vlans = 4096,
-+              .enabled_ports = 0x1f,
-+              .cpu_port = B53_CPU_PORT_25, // TODO: auto detect
-+              .vta_regs = B53_VTA_REGS,
-+              .duplex_reg = B53_DUPLEX_STAT_GE,
-+              .jumbo_pm_reg = B53_JUMBO_PORT_MASK,
-+              .jumbo_size_reg = B53_JUMBO_MAX_SIZE,
-+              .sw_ops = &b53_switch_ops,
-+      },
-+};
-+
-+static int b53_switch_init(struct b53_device *dev)
-+{
-+      struct switch_dev *sw_dev = &dev->sw_dev;
-+      unsigned i;
-+      int ret;
-+
-+      for (i = 0; i < ARRAY_SIZE(b53_switch_chips); i++) {
-+              const struct b53_chip_data *chip = &b53_switch_chips[i];
-+
-+              if (chip->chip_id == dev->chip_id) {
-+                      sw_dev->name = chip->dev_name;
-+                      if (!sw_dev->alias)
-+                              sw_dev->alias = chip->alias;
-+                      if (!dev->enabled_ports)
-+                              dev->enabled_ports = chip->enabled_ports;
-+                      dev->duplex_reg = chip->duplex_reg;
-+                      dev->vta_regs[0] = chip->vta_regs[0];
-+                      dev->vta_regs[1] = chip->vta_regs[1];
-+                      dev->vta_regs[2] = chip->vta_regs[2];
-+                      dev->jumbo_pm_reg = chip->jumbo_pm_reg;
-+                      sw_dev->ops = chip->sw_ops;
-+                      sw_dev->cpu_port = chip->cpu_port;
-+                      sw_dev->vlans = chip->vlans;
-+                      break;
-+              }
-+      }
-+
-+      if (!sw_dev->name)
-+              return -EINVAL;
-+
-+      /* check which BCM5325x version we have */
-+      if (is5325(dev)) {
-+              u8 vc4;
-+
-+              b53_read8(dev, B53_VLAN_PAGE, B53_VLAN_CTRL4_25, &vc4);
-+
-+              /* check reserved bits */
-+              switch (vc4 & 3) {
-+              case 1:
-+                      /* BCM5325E */
-+                      break;
-+              case 3:
-+                      /* BCM5325F - do not use port 4 */
-+                      dev->enabled_ports &= ~BIT(4);
-+                      break;
-+              default:
-+/* On the BCM47XX SoCs this is the supported internal switch.*/
-+#ifndef CONFIG_BCM47XX
-+                      /* BCM5325M */
-+                      return -EINVAL;
-+#else
-+                      break;
-+#endif
-+              }
-+      } else if (dev->chip_id == BCM53115_DEVICE_ID) {
-+              u64 strap_value;
-+
-+              b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value);
-+              /* use second IMP port if GMII is enabled */
-+              if (strap_value & SV_GMII_CTRL_115)
-+                      sw_dev->cpu_port = 5;
-+      }
-+
-+      /* cpu port is always last */
-+      sw_dev->ports = sw_dev->cpu_port + 1;
-+      dev->enabled_ports |= BIT(sw_dev->cpu_port);
-+
-+      dev->ports = devm_kzalloc(dev->dev,
-+                                sizeof(struct b53_port) * sw_dev->ports,
-+                                GFP_KERNEL);
-+      if (!dev->ports)
-+              return -ENOMEM;
-+
-+      dev->vlans = devm_kzalloc(dev->dev,
-+                                sizeof(struct b53_vlan) * sw_dev->vlans,
-+                                GFP_KERNEL);
-+      if (!dev->vlans)
-+              return -ENOMEM;
-+
-+      dev->buf = devm_kzalloc(dev->dev, B53_BUF_SIZE, GFP_KERNEL);
-+      if (!dev->buf)
-+              return -ENOMEM;
-+
-+      dev->reset_gpio = b53_switch_get_reset_gpio(dev);
-+      if (dev->reset_gpio >= 0) {
-+              ret = devm_gpio_request_one(dev->dev, dev->reset_gpio, GPIOF_OUT_INIT_HIGH, "robo_reset");
-+              if (ret)
-+                      return ret;
-+      }
-+
-+      return b53_switch_reset(dev);
-+}
-+
-+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
-+                                  void *priv)
-+{
-+      struct b53_device *dev;
-+
-+      dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL);
-+      if (!dev)
-+              return NULL;
-+
-+      dev->dev = base;
-+      dev->ops = ops;
-+      dev->priv = priv;
-+      mutex_init(&dev->reg_mutex);
-+
-+      return dev;
-+}
-+EXPORT_SYMBOL(b53_switch_alloc);
-+
-+int b53_switch_detect(struct b53_device *dev)
-+{
-+      u32 id32;
-+      u16 tmp;
-+      u8 id8;
-+      int ret;
-+
-+      ret = b53_read8(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id8);
-+      if (ret)
-+              return ret;
-+
-+      switch (id8) {
-+      case 0:
-+              /*
-+               * BCM5325 and BCM5365 do not have this register so reads
-+               * return 0. But the read operation did succeed, so assume
-+               * this is one of them.
-+               *
-+               * Next check if we can write to the 5325's VTA register; for
-+               * 5365 it is read only.
-+               */
-+
-+              b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, 0xf);
-+              b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_TABLE_ACCESS_25, &tmp);
-+
-+              if (tmp == 0xf)
-+                      dev->chip_id = BCM5325_DEVICE_ID;
-+              else
-+                      dev->chip_id = BCM5365_DEVICE_ID;
-+              break;
-+      case BCM5395_DEVICE_ID:
-+      case BCM5397_DEVICE_ID:
-+      case BCM5398_DEVICE_ID:
-+              dev->chip_id = id8;
-+              break;
-+      default:
-+              ret = b53_read32(dev, B53_MGMT_PAGE, B53_DEVICE_ID, &id32);
-+              if (ret)
-+                      return ret;
-+
-+              switch (id32) {
-+              case BCM53115_DEVICE_ID:
-+              case BCM53125_DEVICE_ID:
-+              case BCM53128_DEVICE_ID:
-+              case BCM53010_DEVICE_ID:
-+              case BCM53011_DEVICE_ID:
-+              case BCM53012_DEVICE_ID:
-+              case BCM53018_DEVICE_ID:
-+              case BCM53019_DEVICE_ID:
-+                      dev->chip_id = id32;
-+                      break;
-+              default:
-+                      pr_err("unsupported switch detected (BCM53%02x/BCM%x)\n",
-+                             id8, id32);
-+                      return -ENODEV;
-+              }
-+      }
-+
-+      if (dev->chip_id == BCM5325_DEVICE_ID)
-+              return b53_read8(dev, B53_STAT_PAGE, B53_REV_ID_25,
-+                               &dev->core_rev);
-+      else
-+              return b53_read8(dev, B53_MGMT_PAGE, B53_REV_ID,
-+                               &dev->core_rev);
-+}
-+EXPORT_SYMBOL(b53_switch_detect);
-+
-+int b53_switch_register(struct b53_device *dev)
-+{
-+      int ret;
-+
-+      if (dev->pdata) {
-+              dev->chip_id = dev->pdata->chip_id;
-+              dev->enabled_ports = dev->pdata->enabled_ports;
-+              dev->sw_dev.alias = dev->pdata->alias;
-+      }
-+
-+      if (!dev->chip_id && b53_switch_detect(dev))
-+              return -EINVAL;
-+
-+      ret = b53_switch_init(dev);
-+      if (ret)
-+              return ret;
-+
-+      pr_info("found switch: %s, rev %i\n", dev->sw_dev.name, dev->core_rev);
-+
-+      return register_switch(&dev->sw_dev, NULL);
-+}
-+EXPORT_SYMBOL(b53_switch_register);
-+
-+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
-+MODULE_DESCRIPTION("B53 switch library");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/net/phy/b53/b53_mdio.c b/drivers/net/phy/b53/b53_mdio.c
-new file mode 100644
-index 0000000..9062115
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_mdio.c
-@@ -0,0 +1,434 @@
-+/*
-+ * B53 register access through MII registers
-+ *
-+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/phy.h>
-+#include <linux/module.h>
-+
-+#include "b53_priv.h"
-+
-+#define B53_PSEUDO_PHY        0x1e /* Register Access Pseudo PHY */
-+
-+/* MII registers */
-+#define REG_MII_PAGE    0x10    /* MII Page register */
-+#define REG_MII_ADDR    0x11    /* MII Address register */
-+#define REG_MII_DATA0   0x18    /* MII Data register 0 */
-+#define REG_MII_DATA1   0x19    /* MII Data register 1 */
-+#define REG_MII_DATA2   0x1a    /* MII Data register 2 */
-+#define REG_MII_DATA3   0x1b    /* MII Data register 3 */
-+
-+#define REG_MII_PAGE_ENABLE     BIT(0)
-+#define REG_MII_ADDR_WRITE      BIT(0)
-+#define REG_MII_ADDR_READ       BIT(1)
-+
-+static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
-+{
-+      int i;
-+      u16 v;
-+      int ret;
-+      struct mii_bus *bus = dev->priv;
-+
-+      if (dev->current_page != page) {
-+              /* set page number */
-+              v = (page << 8) | REG_MII_PAGE_ENABLE;
-+              ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v);
-+              if (ret)
-+                      return ret;
-+              dev->current_page = page;
-+      }
-+
-+      /* set register address */
-+      v = (reg << 8) | op;
-+      ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v);
-+      if (ret)
-+              return ret;
-+
-+      /* check if operation completed */
-+      for (i = 0; i < 5; ++i) {
-+              v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR);
-+              if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
-+                      break;
-+              usleep_range(10, 100);
-+      }
-+
-+      if (WARN_ON(i == 5))
-+              return -EIO;
-+
-+      return 0;
-+}
-+
-+static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      int ret;
-+
-+      ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
-+      if (ret)
-+              return ret;
-+
-+      *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff;
-+
-+      return 0;
-+}
-+
-+static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      int ret;
-+
-+      ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
-+      if (ret)
-+              return ret;
-+
-+      *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
-+
-+      return 0;
-+}
-+
-+static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      int ret;
-+
-+      ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
-+      if (ret)
-+              return ret;
-+
-+      *val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
-+      *val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16;
-+
-+      return 0;
-+}
-+
-+static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      u64 temp = 0;
-+      int i;
-+      int ret;
-+
-+      ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
-+      if (ret)
-+              return ret;
-+
-+      for (i = 2; i >= 0; i--) {
-+              temp <<= 16;
-+              temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
-+      }
-+
-+      *val = temp;
-+
-+      return 0;
-+}
-+
-+static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      u64 temp = 0;
-+      int i;
-+      int ret;
-+
-+      ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
-+      if (ret)
-+              return ret;
-+
-+      for (i = 3; i >= 0; i--) {
-+              temp <<= 16;
-+              temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
-+      }
-+
-+      *val = temp;
-+
-+      return 0;
-+}
-+
-+static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      int ret;
-+
-+      ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
-+      if (ret)
-+              return ret;
-+
-+      return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
-+}
-+
-+static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
-+                           u16 value)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      int ret;
-+
-+      ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
-+      if (ret)
-+              return ret;
-+
-+      return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
-+}
-+
-+static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
-+                                  u32 value)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      unsigned int i;
-+      u32 temp = value;
-+
-+      for (i = 0; i < 2; i++) {
-+              int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
-+                                  temp & 0xffff);
-+              if (ret)
-+                      return ret;
-+              temp >>= 16;
-+      }
-+
-+      return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
-+
-+}
-+
-+static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
-+                                  u64 value)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      unsigned i;
-+      u64 temp = value;
-+
-+      for (i = 0; i < 3; i++) {
-+              int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
-+                                  temp & 0xffff);
-+              if (ret)
-+                      return ret;
-+              temp >>= 16;
-+      }
-+
-+      return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
-+
-+}
-+
-+static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
-+                           u64 value)
-+{
-+      struct mii_bus *bus = dev->priv;
-+      unsigned i;
-+      u64 temp = value;
-+
-+      for (i = 0; i < 4; i++) {
-+              int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
-+                                  temp & 0xffff);
-+              if (ret)
-+                      return ret;
-+              temp >>= 16;
-+      }
-+
-+      return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
-+}
-+
-+static struct b53_io_ops b53_mdio_ops = {
-+      .read8 = b53_mdio_read8,
-+      .read16 = b53_mdio_read16,
-+      .read32 = b53_mdio_read32,
-+      .read48 = b53_mdio_read48,
-+      .read64 = b53_mdio_read64,
-+      .write8 = b53_mdio_write8,
-+      .write16 = b53_mdio_write16,
-+      .write32 = b53_mdio_write32,
-+      .write48 = b53_mdio_write48,
-+      .write64 = b53_mdio_write64,
-+};
-+
-+static int b53_phy_probe(struct phy_device *phydev)
-+{
-+      struct b53_device dev;
-+      int ret;
-+
-+      /* allow the generic phy driver to take over */
-+      if (phydev->addr != B53_PSEUDO_PHY && phydev->addr != 0)
-+              return -ENODEV;
-+
-+      dev.current_page = 0xff;
-+      dev.priv = phydev->bus;
-+      dev.ops = &b53_mdio_ops;
-+      dev.pdata = NULL;
-+      mutex_init(&dev.reg_mutex);
-+
-+      ret = b53_switch_detect(&dev);
-+      if (ret)
-+              return ret;
-+
-+      if (is5325(&dev) || is5365(&dev))
-+              phydev->supported = SUPPORTED_100baseT_Full;
-+      else
-+              phydev->supported = SUPPORTED_1000baseT_Full;
-+
-+      phydev->advertising = phydev->supported;
-+
-+      return 0;
-+}
-+
-+static int b53_phy_config_init(struct phy_device *phydev)
-+{
-+      struct b53_device *dev;
-+      int ret;
-+
-+      dev = b53_switch_alloc(&phydev->dev, &b53_mdio_ops, phydev->bus);
-+      if (!dev)
-+              return -ENOMEM;
-+
-+      /* we don't use page 0xff, so force a page set */
-+      dev->current_page = 0xff;
-+      /* force the ethX as alias */
-+      dev->sw_dev.alias = phydev->attached_dev->name;
-+
-+      ret = b53_switch_register(dev);
-+      if (ret) {
-+              dev_err(dev->dev, "failed to register switch: %i\n", ret);
-+              return ret;
-+      }
-+
-+      phydev->priv = dev;
-+
-+      return 0;
-+}
-+
-+static void b53_phy_remove(struct phy_device *phydev)
-+{
-+      struct b53_device *priv = phydev->priv;
-+
-+      if (!priv)
-+              return;
-+
-+      b53_switch_remove(priv);
-+
-+      phydev->priv = NULL;
-+}
-+
-+static int b53_phy_config_aneg(struct phy_device *phydev)
-+{
-+      return 0;
-+}
-+
-+static int b53_phy_read_status(struct phy_device *phydev)
-+{
-+      struct b53_device *priv = phydev->priv;
-+
-+      if (is5325(priv) || is5365(priv))
-+              phydev->speed = 100;
-+      else
-+              phydev->speed = 1000;
-+
-+      phydev->duplex = DUPLEX_FULL;
-+      phydev->link = 1;
-+      phydev->state = PHY_RUNNING;
-+
-+      netif_carrier_on(phydev->attached_dev);
-+      phydev->adjust_link(phydev->attached_dev);
-+
-+      return 0;
-+}
-+
-+/* BCM5325, BCM539x */
-+static struct phy_driver b53_phy_driver_id1 = {
-+      .phy_id         = 0x0143bc00,
-+      .name           = "Broadcom B53 (1)",
-+      .phy_id_mask    = 0x1ffffc00,
-+      .features       = 0,
-+      .probe          = b53_phy_probe,
-+      .remove         = b53_phy_remove,
-+      .config_aneg    = b53_phy_config_aneg,
-+      .config_init    = b53_phy_config_init,
-+      .read_status    = b53_phy_read_status,
-+      .driver = {
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+/* BCM53125, BCM53128 */
-+static struct phy_driver b53_phy_driver_id2 = {
-+      .phy_id         = 0x03625c00,
-+      .name           = "Broadcom B53 (2)",
-+      .phy_id_mask    = 0x1ffffc00,
-+      .features       = 0,
-+      .probe          = b53_phy_probe,
-+      .remove         = b53_phy_remove,
-+      .config_aneg    = b53_phy_config_aneg,
-+      .config_init    = b53_phy_config_init,
-+      .read_status    = b53_phy_read_status,
-+      .driver = {
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+/* BCM5365 */
-+static struct phy_driver b53_phy_driver_id3 = {
-+      .phy_id         = 0x00406000,
-+      .name           = "Broadcom B53 (3)",
-+      .phy_id_mask    = 0x1ffffc00,
-+      .features       = 0,
-+      .probe          = b53_phy_probe,
-+      .remove         = b53_phy_remove,
-+      .config_aneg    = b53_phy_config_aneg,
-+      .config_init    = b53_phy_config_init,
-+      .read_status    = b53_phy_read_status,
-+      .driver = {
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+int __init b53_phy_driver_register(void)
-+{
-+      int ret;
-+
-+      ret = phy_driver_register(&b53_phy_driver_id1);
-+      if (ret)
-+              return ret;
-+
-+      ret = phy_driver_register(&b53_phy_driver_id2);
-+      if (ret)
-+              goto err1;
-+
-+      ret = phy_driver_register(&b53_phy_driver_id3);
-+      if (!ret)
-+              return 0;
-+
-+      phy_driver_unregister(&b53_phy_driver_id2);
-+err1:
-+      phy_driver_unregister(&b53_phy_driver_id1);
-+      return ret;
-+}
-+
-+void __exit b53_phy_driver_unregister(void)
-+{
-+      phy_driver_unregister(&b53_phy_driver_id3);
-+      phy_driver_unregister(&b53_phy_driver_id2);
-+      phy_driver_unregister(&b53_phy_driver_id1);
-+}
-+
-+module_init(b53_phy_driver_register);
-+module_exit(b53_phy_driver_unregister);
-+
-+static struct mdio_device_id __maybe_unused b53_mdio_tbl[] = {
-+      { 0x0143bc00, 0x1ffffc00 },
-+      { 0x03625c00, 0x1ffffc00 },
-+      { 0x00406000, 0x1ffffc00 },
-+      { }
-+};
-+
-+
-+MODULE_DESCRIPTION("B53 MDIO access driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_DEVICE_TABLE(mdio, b53_mdio_tbl);
-diff --git a/drivers/net/phy/b53/b53_mmap.c b/drivers/net/phy/b53/b53_mmap.c
-new file mode 100644
-index 0000000..272360f
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_mmap.c
-@@ -0,0 +1,240 @@
-+/*
-+ * B53 register access through memory mapped registers
-+ *
-+ * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/platform_data/b53.h>
-+
-+#include "b53_priv.h"
-+
-+static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      *val = readb(regs + (page << 8) + reg);
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      if (WARN_ON(reg % 2))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian)
-+              *val = readw_be(regs + (page << 8) + reg);
-+      else
-+              *val = readw(regs + (page << 8) + reg);
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      if (WARN_ON(reg % 4))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian)
-+              *val = readl_be(regs + (page << 8) + reg);
-+      else
-+              *val = readl(regs + (page << 8) + reg);
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      if (WARN_ON(reg % 4))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian) {
-+              *val = readl_be(regs + (page << 8) + reg);
-+              *val <<= 16;
-+              *val |= readw_be(regs + (page << 8) + reg + 4);
-+      } else {
-+              *val |= readw(regs + (page << 8) + reg + 4);
-+              *val <<= 32;
-+              *val = readl(regs + (page << 8) + reg);
-+      }
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      u32 hi, lo;
-+
-+      if (WARN_ON(reg % 4))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian) {
-+              lo = readl_be(regs + (page << 8) + reg);
-+              hi = readl_be(regs + (page << 8) + reg + 4);
-+      } else {
-+              lo = readl(regs + (page << 8) + reg);
-+              hi = readl(regs + (page << 8) + reg + 4);
-+      }
-+
-+      *val = ((u64)hi << 32) | lo;
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      writeb(value, regs + (page << 8) + reg);
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
-+                           u16 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      if (WARN_ON(reg % 2))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian)
-+              writew_be(value, regs + (page << 8) + reg);
-+      else
-+              writew(value, regs + (page << 8) + reg);
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
-+                                  u32 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      if (WARN_ON(reg % 4))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian)
-+              writel_be(value, regs + (page << 8) + reg);
-+      else
-+              writel(value, regs + (page << 8) + reg);
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
-+                                  u64 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      if (WARN_ON(reg % 4))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian) {
-+              writel_be((u32)(value >> 16), regs + (page << 8) + reg);
-+              writew_be((u16)value, regs + (page << 8) + reg + 4);
-+      } else {
-+              writel((u32)value, regs + (page << 8) + reg);
-+              writew((u16)(value >> 32), regs + (page << 8) + reg + 4);
-+      }
-+
-+      return 0;
-+}
-+
-+static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
-+                           u64 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+
-+      if (WARN_ON(reg % 4))
-+              return -EINVAL;
-+
-+      if (dev->pdata && dev->pdata->big_endian) {
-+              writel_be((u32)(value >> 32), regs + (page << 8) + reg);
-+              writel_be((u32)value, regs + (page << 8) + reg + 4);
-+      } else {
-+              writel((u32)value, regs + (page << 8) + reg);
-+              writel((u32)(value >> 32), regs + (page << 8) + reg + 4);
-+      }
-+
-+      return 0;
-+}
-+
-+static struct b53_io_ops b53_mmap_ops = {
-+      .read8 = b53_mmap_read8,
-+      .read16 = b53_mmap_read16,
-+      .read32 = b53_mmap_read32,
-+      .read48 = b53_mmap_read48,
-+      .read64 = b53_mmap_read64,
-+      .write8 = b53_mmap_write8,
-+      .write16 = b53_mmap_write16,
-+      .write32 = b53_mmap_write32,
-+      .write48 = b53_mmap_write48,
-+      .write64 = b53_mmap_write64,
-+};
-+
-+static int b53_mmap_probe(struct platform_device *pdev)
-+{
-+      struct b53_platform_data *pdata = pdev->dev.platform_data;
-+      struct b53_device *dev;
-+
-+      if (!pdata)
-+              return -EINVAL;
-+
-+      dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
-+      if (!dev)
-+              return -ENOMEM;
-+
-+      if (pdata)
-+              dev->pdata = pdata;
-+
-+      platform_set_drvdata(pdev, dev);
-+
-+      return b53_switch_register(dev);
-+}
-+
-+static int b53_mmap_remove(struct platform_device *pdev)
-+{
-+      struct b53_device *dev = platform_get_drvdata(pdev);
-+
-+      if (dev) {
-+              b53_switch_remove(dev);
-+      }
-+
-+      return 0;
-+}
-+
-+static struct platform_driver b53_mmap_driver = {
-+      .probe = b53_mmap_probe,
-+      .remove = b53_mmap_remove,
-+      .driver = {
-+              .name = "b53-switch",
-+      },
-+};
-+
-+module_platform_driver(b53_mmap_driver);
-+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
-+MODULE_DESCRIPTION("B53 MMAP access driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/net/phy/b53/b53_phy_fixup.c b/drivers/net/phy/b53/b53_phy_fixup.c
-new file mode 100644
-index 0000000..72d1373
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_phy_fixup.c
-@@ -0,0 +1,55 @@
-+/*
-+ * B53 PHY Fixup call
-+ *
-+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/phy.h>
-+
-+#define B53_PSEUDO_PHY        0x1e /* Register Access Pseudo PHY */
-+
-+#define B53_BRCM_OUI_1        0x0143bc00
-+#define B53_BRCM_OUI_2        0x03625c00
-+#define B53_BRCM_OUI_3        0x00406000
-+
-+static int b53_phy_fixup(struct phy_device *dev)
-+{
-+      u32 phy_id;
-+      struct mii_bus *bus = dev->bus;
-+
-+      if (dev->addr != B53_PSEUDO_PHY)
-+              return 0;
-+
-+      /* read the first port's id */
-+      phy_id = mdiobus_read(bus, 0, 2) << 16;
-+      phy_id |= mdiobus_read(bus, 0, 3);
-+
-+      if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 ||
-+          (phy_id & 0xfffffc00) == B53_BRCM_OUI_2 ||
-+          (phy_id & 0xfffffc00) == B53_BRCM_OUI_3) {
-+              dev->phy_id = phy_id;
-+      }
-+
-+      return 0;
-+}
-+
-+int __init b53_phy_fixup_register(void)
-+{
-+      return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup);
-+}
-+
-+subsys_initcall(b53_phy_fixup_register);
-diff --git a/drivers/net/phy/b53/b53_priv.h b/drivers/net/phy/b53/b53_priv.h
-new file mode 100644
-index 0000000..bc9b533
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_priv.h
-@@ -0,0 +1,324 @@
-+/*
-+ * B53 common definitions
-+ *
-+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#ifndef __B53_PRIV_H
-+#define __B53_PRIV_H
-+
-+#include <linux/kernel.h>
-+#include <linux/mutex.h>
-+#include <linux/switch.h>
-+
-+struct b53_device;
-+
-+struct b53_io_ops {
-+      int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
-+      int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
-+      int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
-+      int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
-+      int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
-+      int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
-+      int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
-+      int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
-+      int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
-+      int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
-+};
-+
-+enum {
-+      BCM5325_DEVICE_ID = 0x25,
-+      BCM5365_DEVICE_ID = 0x65,
-+      BCM5395_DEVICE_ID = 0x95,
-+      BCM5397_DEVICE_ID = 0x97,
-+      BCM5398_DEVICE_ID = 0x98,
-+      BCM53115_DEVICE_ID = 0x53115,
-+      BCM53125_DEVICE_ID = 0x53125,
-+      BCM53128_DEVICE_ID = 0x53128,
-+      BCM63XX_DEVICE_ID = 0x6300,
-+      BCM53010_DEVICE_ID = 0x53010,
-+      BCM53011_DEVICE_ID = 0x53011,
-+      BCM53012_DEVICE_ID = 0x53012,
-+      BCM53018_DEVICE_ID = 0x53018,
-+      BCM53019_DEVICE_ID = 0x53019,
-+};
-+
-+#define B53_N_PORTS   9
-+#define B53_N_PORTS_25        6
-+
-+struct b53_vlan {
-+      unsigned int    members:B53_N_PORTS;
-+      unsigned int    untag:B53_N_PORTS;
-+};
-+
-+struct b53_port {
-+      unsigned int    pvid:12;
-+};
-+
-+struct b53_device {
-+      struct switch_dev sw_dev;
-+      struct b53_platform_data *pdata;
-+
-+      struct mutex reg_mutex;
-+      const struct b53_io_ops *ops;
-+
-+      /* chip specific data */
-+      u32 chip_id;
-+      u8 core_rev;
-+      u8 vta_regs[3];
-+      u8 duplex_reg;
-+      u8 jumbo_pm_reg;
-+      u8 jumbo_size_reg;
-+      int reset_gpio;
-+
-+      /* used ports mask */
-+      u16 enabled_ports;
-+
-+      /* connect specific data */
-+      u8 current_page;
-+      struct device *dev;
-+      void *priv;
-+
-+      /* run time configuration */
-+      unsigned enable_vlan:1;
-+      unsigned enable_jumbo:1;
-+      unsigned allow_vid_4095:1;
-+
-+      struct b53_port *ports;
-+      struct b53_vlan *vlans;
-+
-+      char *buf;
-+};
-+
-+#define b53_for_each_port(dev, i) \
-+      for (i = 0; i < B53_N_PORTS; i++) \
-+              if (dev->enabled_ports & BIT(i))
-+
-+
-+
-+static inline int is5325(struct b53_device *dev)
-+{
-+      return dev->chip_id == BCM5325_DEVICE_ID;
-+}
-+
-+static inline int is5365(struct b53_device *dev)
-+{
-+#ifdef CONFIG_BCM47XX
-+      return dev->chip_id == BCM5365_DEVICE_ID;
-+#else
-+      return 0;
-+#endif
-+}
-+
-+static inline int is5397_98(struct b53_device *dev)
-+{
-+      return dev->chip_id == BCM5397_DEVICE_ID ||
-+              dev->chip_id == BCM5398_DEVICE_ID;
-+}
-+
-+static inline int is539x(struct b53_device *dev)
-+{
-+      return dev->chip_id == BCM5395_DEVICE_ID ||
-+              dev->chip_id == BCM5397_DEVICE_ID ||
-+              dev->chip_id == BCM5398_DEVICE_ID;
-+}
-+
-+static inline int is531x5(struct b53_device *dev)
-+{
-+      return dev->chip_id == BCM53115_DEVICE_ID ||
-+              dev->chip_id == BCM53125_DEVICE_ID ||
-+              dev->chip_id == BCM53128_DEVICE_ID;
-+}
-+
-+static inline int is63xx(struct b53_device *dev)
-+{
-+#ifdef CONFIG_BCM63XX
-+      return dev->chip_id == BCM63XX_DEVICE_ID;
-+#else
-+      return 0;
-+#endif
-+}
-+      
-+static inline int is5301x(struct b53_device *dev)
-+{
-+      return dev->chip_id == BCM53010_DEVICE_ID ||
-+              dev->chip_id == BCM53011_DEVICE_ID ||
-+              dev->chip_id == BCM53012_DEVICE_ID ||
-+              dev->chip_id == BCM53018_DEVICE_ID ||
-+              dev->chip_id == BCM53019_DEVICE_ID;
-+}
-+
-+#define B53_CPU_PORT_25       5
-+#define B53_CPU_PORT  8
-+
-+static inline int is_cpu_port(struct b53_device *dev, int port)
-+{
-+      return dev->sw_dev.cpu_port == port;
-+}
-+
-+static inline struct b53_device *sw_to_b53(struct switch_dev *sw)
-+{
-+      return container_of(sw, struct b53_device, sw_dev);
-+}
-+
-+struct b53_device *b53_switch_alloc(struct device *base, struct b53_io_ops *ops,
-+                                  void *priv);
-+
-+int b53_switch_detect(struct b53_device *dev);
-+
-+int b53_switch_register(struct b53_device *dev);
-+
-+static inline void b53_switch_remove(struct b53_device *dev)
-+{
-+      unregister_switch(&dev->sw_dev);
-+}
-+
-+static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->read8(dev, page, reg, val);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->read16(dev, page, reg, val);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->read32(dev, page, reg, val);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->read48(dev, page, reg, val);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->read64(dev, page, reg, val);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->write8(dev, page, reg, value);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
-+                            u16 value)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->write16(dev, page, reg, value);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
-+                            u32 value)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->write32(dev, page, reg, value);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
-+                            u64 value)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->write48(dev, page, reg, value);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
-+                             u64 value)
-+{
-+      int ret;
-+
-+      mutex_lock(&dev->reg_mutex);
-+      ret = dev->ops->write64(dev, page, reg, value);
-+      mutex_unlock(&dev->reg_mutex);
-+
-+      return ret;
-+}
-+
-+#ifdef CONFIG_BCM47XX
-+
-+#include <bcm47xx_nvram.h>
-+#include <bcm47xx_board.h>
-+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
-+{
-+      enum bcm47xx_board board = bcm47xx_board_get();
-+
-+      switch (board) {
-+      case BCM47XX_BOARD_LINKSYS_WRT300NV11:
-+      case BCM47XX_BOARD_LINKSYS_WRT310NV1:
-+              return 8;
-+      default:
-+              return bcm47xx_nvram_gpio_pin("robo_reset");
-+      }
-+}
-+#else
-+static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
-+{
-+      return -ENOENT;
-+}
-+#endif
-+#endif
-diff --git a/drivers/net/phy/b53/b53_regs.h b/drivers/net/phy/b53/b53_regs.h
-new file mode 100644
-index 0000000..ba50915
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_regs.h
-@@ -0,0 +1,313 @@
-+/*
-+ * B53 register definitions
-+ *
-+ * Copyright (C) 2004 Broadcom Corporation
-+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#ifndef __B53_REGS_H
-+#define __B53_REGS_H
-+
-+/* Management Port (SMP) Page offsets */
-+#define B53_CTRL_PAGE                 0x00 /* Control */
-+#define B53_STAT_PAGE                 0x01 /* Status */
-+#define B53_MGMT_PAGE                 0x02 /* Management Mode */
-+#define B53_MIB_AC_PAGE                       0x03 /* MIB Autocast */
-+#define B53_ARLCTRL_PAGE              0x04 /* ARL Control */
-+#define B53_ARLIO_PAGE                        0x05 /* ARL Access */
-+#define B53_FRAMEBUF_PAGE             0x06 /* Management frame access */
-+#define B53_MEM_ACCESS_PAGE           0x08 /* Memory access */
-+
-+/* PHY Registers */
-+#define B53_PORT_MII_PAGE(i)          (0x10 + i) /* Port i MII Registers */
-+#define B53_IM_PORT_PAGE              0x18 /* Inverse MII Port (to EMAC) */
-+#define B53_ALL_PORT_PAGE             0x19 /* All ports MII (broadcast) */
-+
-+/* MIB registers */
-+#define B53_MIB_PAGE(i)                       (0x20 + i)
-+
-+/* Quality of Service (QoS) Registers */
-+#define B53_QOS_PAGE                  0x30
-+
-+/* Port VLAN Page */
-+#define B53_PVLAN_PAGE                        0x31
-+
-+/* VLAN Registers */
-+#define B53_VLAN_PAGE                 0x34
-+
-+/* Jumbo Frame Registers */
-+#define B53_JUMBO_PAGE                        0x40
-+
-+/*************************************************************************
-+ * Control Page registers
-+ *************************************************************************/
-+
-+/* Port Control Register (8 bit) */
-+#define B53_PORT_CTRL(i)              (0x00 + i)
-+#define   PORT_CTRL_RX_DISABLE                BIT(0)
-+#define   PORT_CTRL_TX_DISABLE                BIT(1)
-+#define   PORT_CTRL_RX_BCST_EN                BIT(2) /* Broadcast RX (P8 only) */
-+#define   PORT_CTRL_RX_MCST_EN                BIT(3) /* Multicast RX (P8 only) */
-+#define   PORT_CTRL_RX_UCST_EN                BIT(4) /* Unicast RX (P8 only) */
-+#define         PORT_CTRL_STP_STATE_S         5
-+#define   PORT_CTRL_STP_STATE_MASK    (0x3 << PORT_CTRL_STP_STATE_S)
-+
-+/* SMP Control Register (8 bit) */
-+#define B53_SMP_CTRL                  0x0a
-+
-+/* Switch Mode Control Register (8 bit) */
-+#define B53_SWITCH_MODE                       0x0b
-+#define   SM_SW_FWD_MODE              BIT(0)  /* 1 = Managed Mode */
-+#define   SM_SW_FWD_EN                        BIT(1)  /* Forwarding Enable */
-+
-+/* IMP Port state override register (8 bit) */
-+#define B53_PORT_OVERRIDE_CTRL                0x0e
-+#define   PORT_OVERRIDE_LINK          BIT(0)
-+#define   PORT_OVERRIDE_HALF_DUPLEX   BIT(1) /* 0 = Full Duplex */
-+#define   PORT_OVERRIDE_SPEED_S               2
-+#define   PORT_OVERRIDE_SPEED_10M     (0 << PORT_OVERRIDE_SPEED_S)
-+#define   PORT_OVERRIDE_SPEED_100M    (1 << PORT_OVERRIDE_SPEED_S)
-+#define   PORT_OVERRIDE_SPEED_1000M   (2 << PORT_OVERRIDE_SPEED_S)
-+#define   PORT_OVERRIDE_RV_MII_25     BIT(4) /* BCM5325 only */
-+#define   PORT_OVERRIDE_RX_FLOW               BIT(4)
-+#define   PORT_OVERRIDE_TX_FLOW               BIT(5)
-+#define   PORT_OVERRIDE_EN            BIT(7) /* Use the register contents */
-+
-+/* Power-down mode control */
-+#define B53_PD_MODE_CTRL_25           0x0f
-+
-+/* IP Multicast control (8 bit) */
-+#define B53_IP_MULTICAST_CTRL         0x21
-+#define  B53_IPMC_FWD_EN              BIT(1)
-+#define  B53_UC_FWD_EN                        BIT(6)
-+#define  B53_MC_FWD_EN                        BIT(7)
-+
-+/* (16 bit) */
-+#define B53_UC_FLOOD_MASK             0x32
-+#define B53_MC_FLOOD_MASK             0x34
-+#define B53_IPMC_FLOOD_MASK           0x36
-+
-+/* Software reset register (8 bit) */
-+#define B53_SOFTRESET                 0x79
-+
-+/* Fast Aging Control register (8 bit) */
-+#define B53_FAST_AGE_CTRL             0x88
-+#define   FAST_AGE_STATIC             BIT(0)
-+#define   FAST_AGE_DYNAMIC            BIT(1)
-+#define   FAST_AGE_PORT                       BIT(2)
-+#define   FAST_AGE_VLAN                       BIT(3)
-+#define   FAST_AGE_STP                        BIT(4)
-+#define   FAST_AGE_MC                 BIT(5)
-+#define   FAST_AGE_DONE                       BIT(7)
-+
-+/*************************************************************************
-+ * Status Page registers
-+ *************************************************************************/
-+
-+/* Link Status Summary Register (16bit) */
-+#define B53_LINK_STAT                 0x00
-+
-+/* Link Status Change Register (16 bit) */
-+#define B53_LINK_STAT_CHANGE          0x02
-+
-+/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
-+#define B53_SPEED_STAT                        0x04
-+#define  SPEED_PORT_FE(reg, port)     (((reg) >> (port)) & 1)
-+#define  SPEED_PORT_GE(reg, port)     (((reg) >> 2 * (port)) & 3)
-+#define  SPEED_STAT_10M                       0
-+#define  SPEED_STAT_100M              1
-+#define  SPEED_STAT_1000M             2
-+
-+/* Duplex Status Summary (16 bit) */
-+#define B53_DUPLEX_STAT_FE            0x06
-+#define B53_DUPLEX_STAT_GE            0x08
-+#define B53_DUPLEX_STAT_63XX          0x0c
-+
-+/* Revision ID register for BCM5325 */
-+#define B53_REV_ID_25                 0x50
-+
-+/* Strap Value (48 bit) */
-+#define B53_STRAP_VALUE                       0x70
-+#define   SV_GMII_CTRL_115            BIT(27)
-+
-+/*************************************************************************
-+ * Management Mode Page Registers
-+ *************************************************************************/
-+
-+/* Global Management Config Register (8 bit) */
-+#define B53_GLOBAL_CONFIG             0x00
-+#define   GC_RESET_MIB                        0x01
-+#define   GC_RX_BPDU_EN                       0x02
-+#define   GC_MIB_AC_HDR_EN            0x10
-+#define   GC_MIB_AC_EN                        0x20
-+#define   GC_FRM_MGMT_PORT_M          0xC0
-+#define   GC_FRM_MGMT_PORT_04         0x00
-+#define   GC_FRM_MGMT_PORT_MII                0x80
-+
-+/* Device ID register (8 or 32 bit) */
-+#define B53_DEVICE_ID                 0x30
-+
-+/* Revision ID register (8 bit) */
-+#define B53_REV_ID                    0x40
-+
-+/*************************************************************************
-+ * ARL Access Page Registers
-+ *************************************************************************/
-+
-+/* VLAN Table Access Register (8 bit) */
-+#define B53_VT_ACCESS                 0x80
-+#define B53_VT_ACCESS_9798            0x60 /* for BCM5397/BCM5398 */
-+#define B53_VT_ACCESS_63XX            0x60 /* for BCM6328/62/68 */
-+#define   VTA_CMD_WRITE                       0
-+#define   VTA_CMD_READ                        1
-+#define   VTA_CMD_CLEAR                       2
-+#define   VTA_START_CMD                       BIT(7)
-+
-+/* VLAN Table Index Register (16 bit) */
-+#define B53_VT_INDEX                  0x81
-+#define B53_VT_INDEX_9798             0x61
-+#define B53_VT_INDEX_63XX             0x62
-+
-+/* VLAN Table Entry Register (32 bit) */
-+#define B53_VT_ENTRY                  0x83
-+#define B53_VT_ENTRY_9798             0x63
-+#define B53_VT_ENTRY_63XX             0x64
-+#define   VTE_MEMBERS                 0x1ff
-+#define   VTE_UNTAG_S                 9
-+#define   VTE_UNTAG                   (0x1ff << 9)
-+
-+/*************************************************************************
-+ * Port VLAN Registers
-+ *************************************************************************/
-+
-+/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
-+#define B53_PVLAN_PORT_MASK(i)                ((i) * 2)
-+
-+/*************************************************************************
-+ * 802.1Q Page Registers
-+ *************************************************************************/
-+
-+/* Global QoS Control (8 bit) */
-+#define B53_QOS_GLOBAL_CTL            0x00
-+
-+/* Enable 802.1Q for individual Ports (16 bit) */
-+#define B53_802_1P_EN                 0x04
-+
-+/*************************************************************************
-+ * VLAN Page Registers
-+ *************************************************************************/
-+
-+/* VLAN Control 0 (8 bit) */
-+#define B53_VLAN_CTRL0                        0x00
-+#define   VC0_8021PF_CTRL_MASK                0x3
-+#define   VC0_8021PF_CTRL_NONE                0x0
-+#define   VC0_8021PF_CTRL_CHANGE_PRI  0x1
-+#define   VC0_8021PF_CTRL_CHANGE_VID  0x2
-+#define   VC0_8021PF_CTRL_CHANGE_BOTH 0x3
-+#define   VC0_8021QF_CTRL_MASK                0xc
-+#define   VC0_8021QF_CTRL_CHANGE_PRI  0x1
-+#define   VC0_8021QF_CTRL_CHANGE_VID  0x2
-+#define   VC0_8021QF_CTRL_CHANGE_BOTH 0x3
-+#define   VC0_RESERVED_1              BIT(1)
-+#define   VC0_DROP_VID_MISS           BIT(4)
-+#define   VC0_VID_HASH_VID            BIT(5)
-+#define   VC0_VID_CHK_EN              BIT(6)  /* Use VID,DA or VID,SA */
-+#define   VC0_VLAN_EN                 BIT(7)  /* 802.1Q VLAN Enabled */
-+
-+/* VLAN Control 1 (8 bit) */
-+#define B53_VLAN_CTRL1                        0x01
-+#define   VC1_RX_MCST_TAG_EN          BIT(1)
-+#define   VC1_RX_MCST_FWD_EN          BIT(2)
-+#define   VC1_RX_MCST_UNTAG_EN                BIT(3)
-+
-+/* VLAN Control 2 (8 bit) */
-+#define B53_VLAN_CTRL2                        0x02
-+
-+/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
-+#define B53_VLAN_CTRL3                        0x03
-+#define B53_VLAN_CTRL3_63XX           0x04
-+#define   VC3_MAXSIZE_1532            BIT(6) /* 5325 only */
-+#define   VC3_HIGH_8BIT_EN            BIT(7) /* 5325 only */
-+
-+/* VLAN Control 4 (8 bit) */
-+#define B53_VLAN_CTRL4                        0x05
-+#define B53_VLAN_CTRL4_25             0x04
-+#define B53_VLAN_CTRL4_63XX           0x06
-+#define   VC4_ING_VID_CHECK_S         6
-+#define   VC4_ING_VID_CHECK_MASK      (0x3 << VC4_ING_VID_CHECK_S)
-+#define   VC4_ING_VID_VIO_FWD         0 /* forward, but do not learn */
-+#define   VC4_ING_VID_VIO_DROP                1 /* drop VID violations */
-+#define   VC4_NO_ING_VID_CHK          2 /* do not check */
-+#define   VC4_ING_VID_VIO_TO_IMP      3 /* redirect to MII port */
-+
-+/* VLAN Control 5 (8 bit) */
-+#define B53_VLAN_CTRL5                        0x06
-+#define B53_VLAN_CTRL5_25             0x05
-+#define B53_VLAN_CTRL5_63XX           0x07
-+#define   VC5_VID_FFF_EN              BIT(2)
-+#define   VC5_DROP_VTABLE_MISS                BIT(3)
-+
-+/* VLAN Control 6 (8 bit) */
-+#define B53_VLAN_CTRL6                        0x07
-+#define B53_VLAN_CTRL6_63XX           0x08
-+
-+/* VLAN Table Access Register (16 bit) */
-+#define B53_VLAN_TABLE_ACCESS_25      0x06    /* BCM5325E/5350 */
-+#define B53_VLAN_TABLE_ACCESS_65      0x08    /* BCM5365 */
-+#define   VTA_VID_LOW_MASK_25         0xf
-+#define   VTA_VID_LOW_MASK_65         0xff
-+#define   VTA_VID_HIGH_S_25           4
-+#define   VTA_VID_HIGH_S_65           8
-+#define   VTA_VID_HIGH_MASK_25                (0xff << VTA_VID_HIGH_S_25E)
-+#define   VTA_VID_HIGH_MASK_65                (0xf << VTA_VID_HIGH_S_65)
-+#define   VTA_RW_STATE                        BIT(12)
-+#define   VTA_RW_STATE_RD             0
-+#define   VTA_RW_STATE_WR             BIT(12)
-+#define   VTA_RW_OP_EN                        BIT(13)
-+
-+/* VLAN Read/Write Registers for (16/32 bit) */
-+#define B53_VLAN_WRITE_25             0x08
-+#define B53_VLAN_WRITE_65             0x0a
-+#define B53_VLAN_READ                 0x0c
-+#define   VA_MEMBER_MASK              0x3f
-+#define   VA_UNTAG_S_25                       6
-+#define   VA_UNTAG_MASK_25            0x3f
-+#define   VA_UNTAG_S_65                       7
-+#define   VA_UNTAG_MASK_65            0x1f
-+#define   VA_VID_HIGH_S                       12
-+#define   VA_VID_HIGH_MASK            (0xffff << VA_VID_HIGH_S)
-+#define   VA_VALID_25                 BIT(20)
-+#define   VA_VALID_25_R4              BIT(24)
-+#define   VA_VALID_65                 BIT(14)
-+
-+/* VLAN Port Default Tag (16 bit) */
-+#define B53_VLAN_PORT_DEF_TAG(i)      (0x10 + 2 * (i))
-+
-+/*************************************************************************
-+ * Jumbo Frame Page Registers
-+ *************************************************************************/
-+
-+/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
-+#define B53_JUMBO_PORT_MASK           0x01
-+#define B53_JUMBO_PORT_MASK_63XX      0x04
-+#define   JPM_10_100_JUMBO_EN         BIT(24) /* GigE always enabled */
-+
-+/* Good Frame Max Size without 802.1Q TAG (16 bit) */
-+#define B53_JUMBO_MAX_SIZE            0x05
-+#define B53_JUMBO_MAX_SIZE_63XX               0x08
-+#define   JMS_MIN_SIZE                        1518
-+#define   JMS_MAX_SIZE                        9724
-+
-+#endif /* !__B53_REGS_H */
-diff --git a/drivers/net/phy/b53/b53_spi.c b/drivers/net/phy/b53/b53_spi.c
-new file mode 100644
-index 0000000..8c6b171
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_spi.c
-@@ -0,0 +1,327 @@
-+/*
-+ * B53 register access through SPI
-+ *
-+ * Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <asm/unaligned.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/spi/spi.h>
-+#include <linux/platform_data/b53.h>
-+
-+#include "b53_priv.h"
-+
-+#define B53_SPI_DATA          0xf0
-+
-+#define B53_SPI_STATUS                0xfe
-+#define B53_SPI_CMD_SPIF      BIT(7)
-+#define B53_SPI_CMD_RACK      BIT(5)
-+
-+#define B53_SPI_CMD_READ      0x00
-+#define B53_SPI_CMD_WRITE     0x01
-+#define B53_SPI_CMD_NORMAL    0x60
-+#define B53_SPI_CMD_FAST      0x10
-+
-+#define B53_SPI_PAGE_SELECT   0xff
-+
-+static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
-+                                   unsigned len)
-+{
-+      u8 txbuf[2];
-+
-+      txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
-+      txbuf[1] = reg;
-+
-+      return spi_write_then_read(spi, txbuf, 2, val, len);
-+}
-+
-+static inline int b53_spi_clear_status(struct spi_device *spi)
-+{
-+      unsigned int i;
-+      u8 rxbuf;
-+      int ret;
-+
-+      for (i = 0; i < 10; i++) {
-+              ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
-+              if (ret)
-+                      return ret;
-+
-+              if (!(rxbuf & B53_SPI_CMD_SPIF))
-+                      break;
-+
-+              mdelay(1);
-+      }
-+
-+      if (i == 10)
-+              return -EIO;
-+
-+      return 0;
-+}
-+
-+static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
-+{
-+      u8 txbuf[3];
-+
-+      txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
-+      txbuf[1] = B53_SPI_PAGE_SELECT;
-+      txbuf[2] = page;
-+
-+      return spi_write(spi, txbuf, sizeof(txbuf));
-+}
-+
-+static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
-+{
-+      int ret = b53_spi_clear_status(spi);
-+      if (ret)
-+              return ret;
-+
-+      return b53_spi_set_page(spi, page);
-+}
-+
-+static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
-+{
-+      u8 rxbuf;
-+      int retry_count;
-+      int ret;
-+
-+      ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
-+      if (ret)
-+              return ret;
-+
-+      for (retry_count = 0; retry_count < 10; retry_count++) {
-+              ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
-+              if (ret)
-+                      return ret;
-+
-+              if (rxbuf & B53_SPI_CMD_RACK)
-+                      break;
-+
-+              mdelay(1);
-+      }
-+
-+      if (retry_count == 10)
-+              return -EIO;
-+
-+      return 0;
-+}
-+
-+static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
-+                      unsigned len)
-+{
-+      struct spi_device *spi = dev->priv;
-+      int ret;
-+
-+      ret = b53_prepare_reg_access(spi, page);
-+      if (ret)
-+              return ret;
-+
-+      ret = b53_spi_prepare_reg_read(spi, reg);
-+      if (ret)
-+              return ret;
-+
-+      return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
-+}
-+
-+static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
-+{
-+      return b53_spi_read(dev, page, reg, val, 1);
-+}
-+
-+static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
-+{
-+      int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
-+      if (!ret)
-+              *val = le16_to_cpu(*val);
-+
-+      return ret;
-+}
-+
-+static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
-+{
-+      int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
-+      if (!ret)
-+              *val = le32_to_cpu(*val);
-+
-+      return ret;
-+}
-+
-+static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      int ret;
-+
-+      *val = 0;
-+      ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
-+      if (!ret)
-+              *val = le64_to_cpu(*val);
-+
-+      return ret;
-+}
-+
-+static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
-+      if (!ret)
-+              *val = le64_to_cpu(*val);
-+
-+      return ret;
-+}
-+
-+static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
-+{
-+      struct spi_device *spi = dev->priv;
-+      int ret;
-+      u8 txbuf[3];
-+
-+      ret = b53_prepare_reg_access(spi, page);
-+      if (ret)
-+              return ret;
-+
-+      txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
-+      txbuf[1] = reg;
-+      txbuf[2] = value;
-+
-+      return spi_write(spi, txbuf, sizeof(txbuf));
-+}
-+
-+static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
-+{
-+      struct spi_device *spi = dev->priv;
-+      int ret;
-+      u8 txbuf[4];
-+
-+      ret = b53_prepare_reg_access(spi, page);
-+      if (ret)
-+              return ret;
-+
-+      txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
-+      txbuf[1] = reg;
-+      put_unaligned_le16(value, &txbuf[2]);
-+
-+      return spi_write(spi, txbuf, sizeof(txbuf));
-+}
-+
-+static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
-+{
-+      struct spi_device *spi = dev->priv;
-+      int ret;
-+      u8 txbuf[6];
-+
-+      ret = b53_prepare_reg_access(spi, page);
-+      if (ret)
-+              return ret;
-+
-+      txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
-+      txbuf[1] = reg;
-+      put_unaligned_le32(value, &txbuf[2]);
-+
-+      return spi_write(spi, txbuf, sizeof(txbuf));
-+}
-+
-+static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
-+{
-+      struct spi_device *spi = dev->priv;
-+      int ret;
-+      u8 txbuf[10];
-+
-+      ret = b53_prepare_reg_access(spi, page);
-+      if (ret)
-+              return ret;
-+
-+      txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
-+      txbuf[1] = reg;
-+      put_unaligned_le64(value, &txbuf[2]);
-+
-+      return spi_write(spi, txbuf, sizeof(txbuf) - 2);
-+}
-+
-+static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
-+{
-+      struct spi_device *spi = dev->priv;
-+      int ret;
-+      u8 txbuf[10];
-+
-+      ret = b53_prepare_reg_access(spi, page);
-+      if (ret)
-+              return ret;
-+
-+      txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
-+      txbuf[1] = reg;
-+      put_unaligned_le64(value, &txbuf[2]);
-+
-+      return spi_write(spi, txbuf, sizeof(txbuf));
-+}
-+
-+static struct b53_io_ops b53_spi_ops = {
-+      .read8 = b53_spi_read8,
-+      .read16 = b53_spi_read16,
-+      .read32 = b53_spi_read32,
-+      .read48 = b53_spi_read48,
-+      .read64 = b53_spi_read64,
-+      .write8 = b53_spi_write8,
-+      .write16 = b53_spi_write16,
-+      .write32 = b53_spi_write32,
-+      .write48 = b53_spi_write48,
-+      .write64 = b53_spi_write64,
-+};
-+
-+static int b53_spi_probe(struct spi_device *spi)
-+{
-+      struct b53_device *dev;
-+      int ret;
-+
-+      dev = b53_switch_alloc(&spi->dev, &b53_spi_ops, spi);
-+      if (!dev)
-+              return -ENOMEM;
-+
-+      if (spi->dev.platform_data)
-+              dev->pdata = spi->dev.platform_data;
-+
-+      ret = b53_switch_register(dev);
-+      if (ret)
-+              return ret;
-+
-+      spi_set_drvdata(spi, dev);
-+
-+      return 0;
-+}
-+
-+static int b53_spi_remove(struct spi_device *spi)
-+{
-+      struct b53_device *dev = spi_get_drvdata(spi);
-+
-+      if (dev) {
-+              b53_switch_remove(dev);
-+      }
-+
-+      return 0;
-+}
-+
-+static struct spi_driver b53_spi_driver = {
-+      .driver = {
-+              .name   = "b53-switch",
-+              .bus    = &spi_bus_type,
-+              .owner  = THIS_MODULE,
-+      },
-+      .probe  = b53_spi_probe,
-+      .remove = b53_spi_remove,
-+};
-+
-+module_spi_driver(b53_spi_driver);
-+
-+MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
-+MODULE_DESCRIPTION("B53 SPI access driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/net/phy/b53/b53_srab.c b/drivers/net/phy/b53/b53_srab.c
-new file mode 100644
-index 0000000..a68e275
---- /dev/null
-+++ b/drivers/net/phy/b53/b53_srab.c
-@@ -0,0 +1,379 @@
-+/*
-+ * B53 register access through Switch Register Access Bridge Registers
-+ *
-+ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/platform_data/b53.h>
-+
-+#include "b53_priv.h"
-+
-+/* command and status register of the SRAB */
-+#define B53_SRAB_CMDSTAT              0x2c
-+#define  B53_SRAB_CMDSTAT_RST         BIT(2)
-+#define  B53_SRAB_CMDSTAT_WRITE               BIT(1)
-+#define  B53_SRAB_CMDSTAT_GORDYN      BIT(0)
-+#define  B53_SRAB_CMDSTAT_PAGE                24
-+#define  B53_SRAB_CMDSTAT_REG         16
-+
-+/* high order word of write data to switch registe */
-+#define B53_SRAB_WD_H                 0x30
-+
-+/* low order word of write data to switch registe */
-+#define B53_SRAB_WD_L                 0x34
-+
-+/* high order word of read data from switch register */
-+#define B53_SRAB_RD_H                 0x38
-+
-+/* low order word of read data from switch register */
-+#define B53_SRAB_RD_L                 0x3c
-+
-+/* command and status register of the SRAB */
-+#define B53_SRAB_CTRLS                        0x40
-+#define  B53_SRAB_CTRLS_RCAREQ                BIT(3)
-+#define  B53_SRAB_CTRLS_RCAGNT                BIT(4)
-+#define  B53_SRAB_CTRLS_SW_INIT_DONE  BIT(6)
-+
-+/* the register captures interrupt pulses from the switch */
-+#define B53_SRAB_INTR                 0x44
-+
-+static int b53_srab_request_grant(struct b53_device *dev)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      u32 ctrls;
-+      int i;
-+
-+      ctrls = readl(regs + B53_SRAB_CTRLS);
-+      ctrls |= B53_SRAB_CTRLS_RCAREQ;
-+      writel(ctrls, regs + B53_SRAB_CTRLS);
-+
-+      for (i = 0; i < 20; i++) {
-+              ctrls = readl(regs + B53_SRAB_CTRLS);
-+              if (ctrls & B53_SRAB_CTRLS_RCAGNT)
-+                      break;
-+              usleep_range(10, 100);
-+      }
-+      if (WARN_ON(i == 5))
-+              return -EIO;
-+
-+      return 0;
-+}
-+
-+static void b53_srab_release_grant(struct b53_device *dev)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      u32 ctrls;
-+
-+      ctrls = readl(regs + B53_SRAB_CTRLS);
-+      ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
-+      writel(ctrls, regs + B53_SRAB_CTRLS);
-+}
-+
-+static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
-+{
-+      int i;
-+      u32 cmdstat;
-+      u8 __iomem *regs = dev->priv;
-+
-+      /* set register address */
-+      cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
-+                (reg << B53_SRAB_CMDSTAT_REG) |
-+                B53_SRAB_CMDSTAT_GORDYN |
-+                op;
-+      writel(cmdstat, regs + B53_SRAB_CMDSTAT);
-+      
-+      /* check if operation completed */
-+      for (i = 0; i < 5; ++i) {
-+              cmdstat = readl(regs + B53_SRAB_CMDSTAT);
-+              if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
-+                      break;
-+              usleep_range(10, 100);
-+      }
-+
-+      if (WARN_ON(i == 5))
-+              return -EIO;
-+
-+      return 0;
-+}
-+
-+static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      ret = b53_srab_op(dev, page, reg, 0);
-+      if (ret)
-+              goto err;
-+
-+      *val = readl(regs + B53_SRAB_RD_L) & 0xff;
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      ret = b53_srab_op(dev, page, reg, 0);
-+      if (ret)
-+              goto err;
-+
-+      *val = readl(regs + B53_SRAB_RD_L) & 0xffff;
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      ret = b53_srab_op(dev, page, reg, 0);
-+      if (ret)
-+              goto err;
-+
-+      *val = readl(regs + B53_SRAB_RD_L);
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      ret = b53_srab_op(dev, page, reg, 0);
-+      if (ret)
-+              goto err;
-+
-+      *val = readl(regs + B53_SRAB_RD_L);
-+      *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
-+      
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      ret = b53_srab_op(dev, page, reg, 0);
-+      if (ret)
-+              goto err;
-+
-+      *val = readl(regs + B53_SRAB_RD_L);
-+      *val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      writel(value, regs + B53_SRAB_WD_L);
-+
-+      ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
-+                           u16 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      writel(value, regs + B53_SRAB_WD_L);
-+
-+      ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
-+                                  u32 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      writel(value, regs + B53_SRAB_WD_L);
-+
-+      ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+
-+}
-+
-+static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
-+                                  u64 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      writel((u32)value, regs + B53_SRAB_WD_L);
-+      writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
-+
-+      ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+
-+}
-+
-+static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
-+                           u64 value)
-+{
-+      u8 __iomem *regs = dev->priv;
-+      int ret = 0;
-+
-+      ret = b53_srab_request_grant(dev);
-+      if (ret)
-+              goto err;
-+
-+      writel((u32)value, regs + B53_SRAB_WD_L);
-+      writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
-+
-+      ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
-+
-+err:
-+      b53_srab_release_grant(dev);
-+
-+      return ret;
-+}
-+
-+static struct b53_io_ops b53_srab_ops = {
-+      .read8 = b53_srab_read8,
-+      .read16 = b53_srab_read16,
-+      .read32 = b53_srab_read32,
-+      .read48 = b53_srab_read48,
-+      .read64 = b53_srab_read64,
-+      .write8 = b53_srab_write8,
-+      .write16 = b53_srab_write16,
-+      .write32 = b53_srab_write32,
-+      .write48 = b53_srab_write48,
-+      .write64 = b53_srab_write64,
-+};
-+
-+static int b53_srab_probe(struct platform_device *pdev)
-+{
-+      struct b53_platform_data *pdata = pdev->dev.platform_data;
-+      struct b53_device *dev;
-+
-+      if (!pdata)
-+              return -EINVAL;
-+
-+      dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs);
-+      if (!dev)
-+              return -ENOMEM;
-+
-+      if (pdata)
-+              dev->pdata = pdata;
-+
-+      platform_set_drvdata(pdev, dev);
-+
-+      return b53_switch_register(dev);
-+}
-+
-+static int b53_srab_remove(struct platform_device *pdev)
-+{
-+      struct b53_device *dev = platform_get_drvdata(pdev);
-+
-+      if (dev) {
-+              b53_switch_remove(dev);
-+      }
-+
-+      return 0;
-+}
-+
-+static struct platform_driver b53_srab_driver = {
-+      .probe = b53_srab_probe,
-+      .remove = b53_srab_remove,
-+      .driver = {
-+              .name = "b53-srab-switch",
-+      },
-+};
-+
-+module_platform_driver(b53_srab_driver);
-+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
-+MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/net/phy/swconfig.c b/drivers/net/phy/swconfig.c
-new file mode 100644
-index 0000000..4f2df4c
---- /dev/null
-+++ b/drivers/net/phy/swconfig.c
-@@ -0,0 +1,1148 @@
-+/*
-+ * swconfig.c: Switch configuration API
-+ *
-+ * 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
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/if.h>
-+#include <linux/if_ether.h>
-+#include <linux/capability.h>
-+#include <linux/skbuff.h>
-+#include <linux/switch.h>
-+#include <linux/of.h>
-+#include <linux/version.h>
-+
-+#define SWCONFIG_DEVNAME      "switch%d"
-+
-+#include "swconfig_leds.c"
-+
-+MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
-+MODULE_LICENSE("GPL");
-+
-+static int swdev_id;
-+static struct list_head swdevs;
-+static DEFINE_SPINLOCK(swdevs_lock);
-+struct swconfig_callback;
-+
-+struct swconfig_callback {
-+      struct sk_buff *msg;
-+      struct genlmsghdr *hdr;
-+      struct genl_info *info;
-+      int cmd;
-+
-+      /* callback for filling in the message data */
-+      int (*fill)(struct swconfig_callback *cb, void *arg);
-+
-+      /* callback for closing the message before sending it */
-+      int (*close)(struct swconfig_callback *cb, void *arg);
-+
-+      struct nlattr *nest[4];
-+      int args[4];
-+};
-+
-+/* defaults */
-+
-+static int
-+swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
-+                      struct switch_val *val)
-+{
-+      int ret;
-+      if (val->port_vlan >= dev->vlans)
-+              return -EINVAL;
-+
-+      if (!dev->ops->get_vlan_ports)
-+              return -EOPNOTSUPP;
-+
-+      ret = dev->ops->get_vlan_ports(dev, val);
-+      return ret;
-+}
-+
-+static int
-+swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
-+                      struct switch_val *val)
-+{
-+      struct switch_port *ports = val->value.ports;
-+      const struct switch_dev_ops *ops = dev->ops;
-+      int i;
-+
-+      if (val->port_vlan >= dev->vlans)
-+              return -EINVAL;
-+
-+      /* validate ports */
-+      if (val->len > dev->ports)
-+              return -EINVAL;
-+
-+      if (!ops->set_vlan_ports)
-+              return -EOPNOTSUPP;
-+
-+      for (i = 0; i < val->len; i++) {
-+              if (ports[i].id >= dev->ports)
-+                      return -EINVAL;
-+
-+              if (ops->set_port_pvid &&
-+                  !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
-+                      ops->set_port_pvid(dev, ports[i].id, val->port_vlan);
-+      }
-+
-+      return ops->set_vlan_ports(dev, val);
-+}
-+
-+static int
-+swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr,
-+                      struct switch_val *val)
-+{
-+      if (val->port_vlan >= dev->ports)
-+              return -EINVAL;
-+
-+      if (!dev->ops->set_port_pvid)
-+              return -EOPNOTSUPP;
-+
-+      return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i);
-+}
-+
-+static int
-+swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr,
-+                      struct switch_val *val)
-+{
-+      if (val->port_vlan >= dev->ports)
-+              return -EINVAL;
-+
-+      if (!dev->ops->get_port_pvid)
-+              return -EOPNOTSUPP;
-+
-+      return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i);
-+}
-+
-+static const char *
-+swconfig_speed_str(enum switch_port_speed speed)
-+{
-+      switch (speed) {
-+      case SWITCH_PORT_SPEED_10:
-+              return "10baseT";
-+      case SWITCH_PORT_SPEED_100:
-+              return "100baseT";
-+      case SWITCH_PORT_SPEED_1000:
-+              return "1000baseT";
-+      default:
-+              break;
-+      }
-+
-+      return "unknown";
-+}
-+
-+static int
-+swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr,
-+                      struct switch_val *val)
-+{
-+      struct switch_port_link link;
-+      int len;
-+      int ret;
-+
-+      if (val->port_vlan >= dev->ports)
-+              return -EINVAL;
-+
-+      if (!dev->ops->get_port_link)
-+              return -EOPNOTSUPP;
-+
-+      memset(&link, 0, sizeof(link));
-+      ret = dev->ops->get_port_link(dev, val->port_vlan, &link);
-+      if (ret)
-+              return ret;
-+
-+      memset(dev->buf, 0, sizeof(dev->buf));
-+
-+      if (link.link)
-+              len = snprintf(dev->buf, sizeof(dev->buf),
-+                             "port:%d link:up speed:%s %s-duplex %s%s%s",
-+                             val->port_vlan,
-+                             swconfig_speed_str(link.speed),
-+                             link.duplex ? "full" : "half",
-+                             link.tx_flow ? "txflow " : "",
-+                             link.rx_flow ?   "rxflow " : "",
-+                             link.aneg ? "auto" : "");
-+      else
-+              len = snprintf(dev->buf, sizeof(dev->buf), "port:%d link:down",
-+                             val->port_vlan);
-+
-+      val->value.s = dev->buf;
-+      val->len = len;
-+
-+      return 0;
-+}
-+
-+static int
-+swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr,
-+                      struct switch_val *val)
-+{
-+      /* don't complain if not supported by the switch driver */
-+      if (!dev->ops->apply_config)
-+              return 0;
-+
-+      return dev->ops->apply_config(dev);
-+}
-+
-+static int
-+swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr,
-+                      struct switch_val *val)
-+{
-+      /* don't complain if not supported by the switch driver */
-+      if (!dev->ops->reset_switch)
-+              return 0;
-+
-+      return dev->ops->reset_switch(dev);
-+}
-+
-+enum global_defaults {
-+      GLOBAL_APPLY,
-+      GLOBAL_RESET,
-+};
-+
-+enum vlan_defaults {
-+      VLAN_PORTS,
-+};
-+
-+enum port_defaults {
-+      PORT_PVID,
-+      PORT_LINK,
-+};
-+
-+static struct switch_attr default_global[] = {
-+      [GLOBAL_APPLY] = {
-+              .type = SWITCH_TYPE_NOVAL,
-+              .name = "apply",
-+              .description = "Activate changes in the hardware",
-+              .set = swconfig_apply_config,
-+      },
-+      [GLOBAL_RESET] = {
-+              .type = SWITCH_TYPE_NOVAL,
-+              .name = "reset",
-+              .description = "Reset the switch",
-+              .set = swconfig_reset_switch,
-+      }
-+};
-+
-+static struct switch_attr default_port[] = {
-+      [PORT_PVID] = {
-+              .type = SWITCH_TYPE_INT,
-+              .name = "pvid",
-+              .description = "Primary VLAN ID",
-+              .set = swconfig_set_pvid,
-+              .get = swconfig_get_pvid,
-+      },
-+      [PORT_LINK] = {
-+              .type = SWITCH_TYPE_STRING,
-+              .name = "link",
-+              .description = "Get port link information",
-+              .set = NULL,
-+              .get = swconfig_get_link,
-+      }
-+};
-+
-+static struct switch_attr default_vlan[] = {
-+      [VLAN_PORTS] = {
-+              .type = SWITCH_TYPE_PORTS,
-+              .name = "ports",
-+              .description = "VLAN port mapping",
-+              .set = swconfig_set_vlan_ports,
-+              .get = swconfig_get_vlan_ports,
-+      },
-+};
-+
-+static const struct switch_attr *
-+swconfig_find_attr_by_name(const struct switch_attrlist *alist,
-+                              const char *name)
-+{
-+      int i;
-+
-+      for (i = 0; i < alist->n_attr; i++)
-+              if (strcmp(name, alist->attr[i].name) == 0)
-+                      return &alist->attr[i];
-+
-+      return NULL;
-+}
-+
-+static void swconfig_defaults_init(struct switch_dev *dev)
-+{
-+      const struct switch_dev_ops *ops = dev->ops;
-+
-+      dev->def_global = 0;
-+      dev->def_vlan = 0;
-+      dev->def_port = 0;
-+
-+      if (ops->get_vlan_ports || ops->set_vlan_ports)
-+              set_bit(VLAN_PORTS, &dev->def_vlan);
-+
-+      if (ops->get_port_pvid || ops->set_port_pvid)
-+              set_bit(PORT_PVID, &dev->def_port);
-+
-+      if (ops->get_port_link &&
-+          !swconfig_find_attr_by_name(&ops->attr_port, "link"))
-+              set_bit(PORT_LINK, &dev->def_port);
-+
-+      /* always present, can be no-op */
-+      set_bit(GLOBAL_APPLY, &dev->def_global);
-+      set_bit(GLOBAL_RESET, &dev->def_global);
-+}
-+
-+
-+static struct genl_family switch_fam = {
-+      .id = GENL_ID_GENERATE,
-+      .name = "switch",
-+      .hdrsize = 0,
-+      .version = 1,
-+      .maxattr = SWITCH_ATTR_MAX,
-+};
-+
-+static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
-+      [SWITCH_ATTR_ID] = { .type = NLA_U32 },
-+      [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
-+      [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
-+      [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
-+      [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
-+      [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
-+      [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
-+      [SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
-+};
-+
-+static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
-+      [SWITCH_PORT_ID] = { .type = NLA_U32 },
-+      [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
-+};
-+
-+static inline void
-+swconfig_lock(void)
-+{
-+      spin_lock(&swdevs_lock);
-+}
-+
-+static inline void
-+swconfig_unlock(void)
-+{
-+      spin_unlock(&swdevs_lock);
-+}
-+
-+static struct switch_dev *
-+swconfig_get_dev(struct genl_info *info)
-+{
-+      struct switch_dev *dev = NULL;
-+      struct switch_dev *p;
-+      int id;
-+
-+      if (!info->attrs[SWITCH_ATTR_ID])
-+              goto done;
-+
-+      id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
-+      swconfig_lock();
-+      list_for_each_entry(p, &swdevs, dev_list) {
-+              if (id != p->id)
-+                      continue;
-+
-+              dev = p;
-+              break;
-+      }
-+      if (dev)
-+              mutex_lock(&dev->sw_mutex);
-+      else
-+              pr_debug("device %d not found\n", id);
-+      swconfig_unlock();
-+done:
-+      return dev;
-+}
-+
-+static inline void
-+swconfig_put_dev(struct switch_dev *dev)
-+{
-+      mutex_unlock(&dev->sw_mutex);
-+}
-+
-+static int
-+swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
-+{
-+      struct switch_attr *op = arg;
-+      struct genl_info *info = cb->info;
-+      struct sk_buff *msg = cb->msg;
-+      int id = cb->args[0];
-+      void *hdr;
-+
-+      hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
-+                      NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
-+      if (IS_ERR(hdr))
-+              return -1;
-+
-+      if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id))
-+              goto nla_put_failure;
-+      if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type))
-+              goto nla_put_failure;
-+      if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name))
-+              goto nla_put_failure;
-+      if (op->description)
-+              if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION,
-+                      op->description))
-+                      goto nla_put_failure;
-+
-+      return genlmsg_end(msg, hdr);
-+nla_put_failure:
-+      genlmsg_cancel(msg, hdr);
-+      return -EMSGSIZE;
-+}
-+
-+/* spread multipart messages across multiple message buffers */
-+static int
-+swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
-+{
-+      struct genl_info *info = cb->info;
-+      int restart = 0;
-+      int err;
-+
-+      do {
-+              if (!cb->msg) {
-+                      cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+                      if (cb->msg == NULL)
-+                              goto error;
-+              }
-+
-+              if (!(cb->fill(cb, arg) < 0))
-+                      break;
-+
-+              /* fill failed, check if this was already the second attempt */
-+              if (restart)
-+                      goto error;
-+
-+              /* try again in a new message, send the current one */
-+              restart = 1;
-+              if (cb->close) {
-+                      if (cb->close(cb, arg) < 0)
-+                              goto error;
-+              }
-+              err = genlmsg_reply(cb->msg, info);
-+              cb->msg = NULL;
-+              if (err < 0)
-+                      goto error;
-+
-+      } while (restart);
-+
-+      return 0;
-+
-+error:
-+      if (cb->msg)
-+              nlmsg_free(cb->msg);
-+      return -1;
-+}
-+
-+static int
-+swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
-+      const struct switch_attrlist *alist;
-+      struct switch_dev *dev;
-+      struct swconfig_callback cb;
-+      int err = -EINVAL;
-+      int i;
-+
-+      /* defaults */
-+      struct switch_attr *def_list;
-+      unsigned long *def_active;
-+      int n_def;
-+
-+      dev = swconfig_get_dev(info);
-+      if (!dev)
-+              return -EINVAL;
-+
-+      switch (hdr->cmd) {
-+      case SWITCH_CMD_LIST_GLOBAL:
-+              alist = &dev->ops->attr_global;
-+              def_list = default_global;
-+              def_active = &dev->def_global;
-+              n_def = ARRAY_SIZE(default_global);
-+              break;
-+      case SWITCH_CMD_LIST_VLAN:
-+              alist = &dev->ops->attr_vlan;
-+              def_list = default_vlan;
-+              def_active = &dev->def_vlan;
-+              n_def = ARRAY_SIZE(default_vlan);
-+              break;
-+      case SWITCH_CMD_LIST_PORT:
-+              alist = &dev->ops->attr_port;
-+              def_list = default_port;
-+              def_active = &dev->def_port;
-+              n_def = ARRAY_SIZE(default_port);
-+              break;
-+      default:
-+              WARN_ON(1);
-+              goto out;
-+      }
-+
-+      memset(&cb, 0, sizeof(cb));
-+      cb.info = info;
-+      cb.fill = swconfig_dump_attr;
-+      for (i = 0; i < alist->n_attr; i++) {
-+              if (alist->attr[i].disabled)
-+                      continue;
-+              cb.args[0] = i;
-+              err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]);
-+              if (err < 0)
-+                      goto error;
-+      }
-+
-+      /* defaults */
-+      for (i = 0; i < n_def; i++) {
-+              if (!test_bit(i, def_active))
-+                      continue;
-+              cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
-+              err = swconfig_send_multipart(&cb, (void *) &def_list[i]);
-+              if (err < 0)
-+                      goto error;
-+      }
-+      swconfig_put_dev(dev);
-+
-+      if (!cb.msg)
-+              return 0;
-+
-+      return genlmsg_reply(cb.msg, info);
-+
-+error:
-+      if (cb.msg)
-+              nlmsg_free(cb.msg);
-+out:
-+      swconfig_put_dev(dev);
-+      return err;
-+}
-+
-+static const struct switch_attr *
-+swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
-+              struct switch_val *val)
-+{
-+      struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
-+      const struct switch_attrlist *alist;
-+      const struct switch_attr *attr = NULL;
-+      int attr_id;
-+
-+      /* defaults */
-+      struct switch_attr *def_list;
-+      unsigned long *def_active;
-+      int n_def;
-+
-+      if (!info->attrs[SWITCH_ATTR_OP_ID])
-+              goto done;
-+
-+      switch (hdr->cmd) {
-+      case SWITCH_CMD_SET_GLOBAL:
-+      case SWITCH_CMD_GET_GLOBAL:
-+              alist = &dev->ops->attr_global;
-+              def_list = default_global;
-+              def_active = &dev->def_global;
-+              n_def = ARRAY_SIZE(default_global);
-+              break;
-+      case SWITCH_CMD_SET_VLAN:
-+      case SWITCH_CMD_GET_VLAN:
-+              alist = &dev->ops->attr_vlan;
-+              def_list = default_vlan;
-+              def_active = &dev->def_vlan;
-+              n_def = ARRAY_SIZE(default_vlan);
-+              if (!info->attrs[SWITCH_ATTR_OP_VLAN])
-+                      goto done;
-+              val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
-+              if (val->port_vlan >= dev->vlans)
-+                      goto done;
-+              break;
-+      case SWITCH_CMD_SET_PORT:
-+      case SWITCH_CMD_GET_PORT:
-+              alist = &dev->ops->attr_port;
-+              def_list = default_port;
-+              def_active = &dev->def_port;
-+              n_def = ARRAY_SIZE(default_port);
-+              if (!info->attrs[SWITCH_ATTR_OP_PORT])
-+                      goto done;
-+              val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
-+              if (val->port_vlan >= dev->ports)
-+                      goto done;
-+              break;
-+      default:
-+              WARN_ON(1);
-+              goto done;
-+      }
-+
-+      if (!alist)
-+              goto done;
-+
-+      attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
-+      if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
-+              attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
-+              if (attr_id >= n_def)
-+                      goto done;
-+              if (!test_bit(attr_id, def_active))
-+                      goto done;
-+              attr = &def_list[attr_id];
-+      } else {
-+              if (attr_id >= alist->n_attr)
-+                      goto done;
-+              attr = &alist->attr[attr_id];
-+      }
-+
-+      if (attr->disabled)
-+              attr = NULL;
-+
-+done:
-+      if (!attr)
-+              pr_debug("attribute lookup failed\n");
-+      val->attr = attr;
-+      return attr;
-+}
-+
-+static int
-+swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
-+              struct switch_val *val, int max)
-+{
-+      struct nlattr *nla;
-+      int rem;
-+
-+      val->len = 0;
-+      nla_for_each_nested(nla, head, rem) {
-+              struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
-+              struct switch_port *port = &val->value.ports[val->len];
-+
-+              if (val->len >= max)
-+                      return -EINVAL;
-+
-+              if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla,
-+                              port_policy))
-+                      return -EINVAL;
-+
-+              if (!tb[SWITCH_PORT_ID])
-+                      return -EINVAL;
-+
-+              port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
-+              if (tb[SWITCH_PORT_FLAG_TAGGED])
-+                      port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
-+              val->len++;
-+      }
-+
-+      return 0;
-+}
-+
-+static int
-+swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
-+{
-+      const struct switch_attr *attr;
-+      struct switch_dev *dev;
-+      struct switch_val val;
-+      int err = -EINVAL;
-+
-+      dev = swconfig_get_dev(info);
-+      if (!dev)
-+              return -EINVAL;
-+
-+      memset(&val, 0, sizeof(val));
-+      attr = swconfig_lookup_attr(dev, info, &val);
-+      if (!attr || !attr->set)
-+              goto error;
-+
-+      val.attr = attr;
-+      switch (attr->type) {
-+      case SWITCH_TYPE_NOVAL:
-+              break;
-+      case SWITCH_TYPE_INT:
-+              if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
-+                      goto error;
-+              val.value.i =
-+                      nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
-+              break;
-+      case SWITCH_TYPE_STRING:
-+              if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
-+                      goto error;
-+              val.value.s =
-+                      nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
-+              break;
-+      case SWITCH_TYPE_PORTS:
-+              val.value.ports = dev->portbuf;
-+              memset(dev->portbuf, 0,
-+                      sizeof(struct switch_port) * dev->ports);
-+
-+              /* TODO: implement multipart? */
-+              if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
-+                      err = swconfig_parse_ports(skb,
-+                              info->attrs[SWITCH_ATTR_OP_VALUE_PORTS],
-+                              &val, dev->ports);
-+                      if (err < 0)
-+                              goto error;
-+              } else {
-+                      val.len = 0;
-+                      err = 0;
-+              }
-+              break;
-+      default:
-+              goto error;
-+      }
-+
-+      err = attr->set(dev, attr, &val);
-+error:
-+      swconfig_put_dev(dev);
-+      return err;
-+}
-+
-+static int
-+swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
-+{
-+      if (cb->nest[0])
-+              nla_nest_end(cb->msg, cb->nest[0]);
-+      return 0;
-+}
-+
-+static int
-+swconfig_send_port(struct swconfig_callback *cb, void *arg)
-+{
-+      const struct switch_port *port = arg;
-+      struct nlattr *p = NULL;
-+
-+      if (!cb->nest[0]) {
-+              cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
-+              if (!cb->nest[0])
-+                      return -1;
-+      }
-+
-+      p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
-+      if (!p)
-+              goto error;
-+
-+      if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id))
-+              goto nla_put_failure;
-+      if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
-+              if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED))
-+                      goto nla_put_failure;
-+      }
-+
-+      nla_nest_end(cb->msg, p);
-+      return 0;
-+
-+nla_put_failure:
-+              nla_nest_cancel(cb->msg, p);
-+error:
-+      nla_nest_cancel(cb->msg, cb->nest[0]);
-+      return -1;
-+}
-+
-+static int
-+swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
-+              const struct switch_val *val)
-+{
-+      struct swconfig_callback cb;
-+      int err = 0;
-+      int i;
-+
-+      if (!val->value.ports)
-+              return -EINVAL;
-+
-+      memset(&cb, 0, sizeof(cb));
-+      cb.cmd = attr;
-+      cb.msg = *msg;
-+      cb.info = info;
-+      cb.fill = swconfig_send_port;
-+      cb.close = swconfig_close_portlist;
-+
-+      cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
-+      for (i = 0; i < val->len; i++) {
-+              err = swconfig_send_multipart(&cb, &val->value.ports[i]);
-+              if (err)
-+                      goto done;
-+      }
-+      err = val->len;
-+      swconfig_close_portlist(&cb, NULL);
-+      *msg = cb.msg;
-+
-+done:
-+      return err;
-+}
-+
-+static int
-+swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
-+{
-+      struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
-+      const struct switch_attr *attr;
-+      struct switch_dev *dev;
-+      struct sk_buff *msg = NULL;
-+      struct switch_val val;
-+      int err = -EINVAL;
-+      int cmd = hdr->cmd;
-+
-+      dev = swconfig_get_dev(info);
-+      if (!dev)
-+              return -EINVAL;
-+
-+      memset(&val, 0, sizeof(val));
-+      attr = swconfig_lookup_attr(dev, info, &val);
-+      if (!attr || !attr->get)
-+              goto error;
-+
-+      if (attr->type == SWITCH_TYPE_PORTS) {
-+              val.value.ports = dev->portbuf;
-+              memset(dev->portbuf, 0,
-+                      sizeof(struct switch_port) * dev->ports);
-+      }
-+
-+      err = attr->get(dev, attr, &val);
-+      if (err)
-+              goto error;
-+
-+      msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
-+      if (!msg)
-+              goto error;
-+
-+      hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
-+                      0, cmd);
-+      if (IS_ERR(hdr))
-+              goto nla_put_failure;
-+
-+      switch (attr->type) {
-+      case SWITCH_TYPE_INT:
-+              if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i))
-+                      goto nla_put_failure;
-+              break;
-+      case SWITCH_TYPE_STRING:
-+              if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s))
-+                      goto nla_put_failure;
-+              break;
-+      case SWITCH_TYPE_PORTS:
-+              err = swconfig_send_ports(&msg, info,
-+                              SWITCH_ATTR_OP_VALUE_PORTS, &val);
-+              if (err < 0)
-+                      goto nla_put_failure;
-+              break;
-+      default:
-+              pr_debug("invalid type in attribute\n");
-+              err = -EINVAL;
-+              goto error;
-+      }
-+      err = genlmsg_end(msg, hdr);
-+      if (err < 0)
-+              goto nla_put_failure;
-+
-+      swconfig_put_dev(dev);
-+      return genlmsg_reply(msg, info);
-+
-+nla_put_failure:
-+      if (msg)
-+              nlmsg_free(msg);
-+error:
-+      swconfig_put_dev(dev);
-+      if (!err)
-+              err = -ENOMEM;
-+      return err;
-+}
-+
-+static int
-+swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
-+              const struct switch_dev *dev)
-+{
-+      struct nlattr *p = NULL, *m = NULL;
-+      void *hdr;
-+      int i;
-+
-+      hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
-+                      SWITCH_CMD_NEW_ATTR);
-+      if (IS_ERR(hdr))
-+              return -1;
-+
-+      if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id))
-+              goto nla_put_failure;
-+      if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname))
-+              goto nla_put_failure;
-+      if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias))
-+              goto nla_put_failure;
-+      if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name))
-+              goto nla_put_failure;
-+      if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans))
-+              goto nla_put_failure;
-+      if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports))
-+              goto nla_put_failure;
-+      if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port))
-+              goto nla_put_failure;
-+
-+      m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP);
-+      if (!m)
-+              goto nla_put_failure;
-+      for (i = 0; i < dev->ports; i++) {
-+              p = nla_nest_start(msg, SWITCH_ATTR_PORTS);
-+              if (!p)
-+                      continue;
-+              if (dev->portmap[i].s) {
-+                      if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT,
-+                                              dev->portmap[i].s))
-+                              goto nla_put_failure;
-+                      if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT,
-+                                              dev->portmap[i].virt))
-+                              goto nla_put_failure;
-+              }
-+              nla_nest_end(msg, p);
-+      }
-+      nla_nest_end(msg, m);
-+      return genlmsg_end(msg, hdr);
-+nla_put_failure:
-+      genlmsg_cancel(msg, hdr);
-+      return -EMSGSIZE;
-+}
-+
-+static int swconfig_dump_switches(struct sk_buff *skb,
-+              struct netlink_callback *cb)
-+{
-+      struct switch_dev *dev;
-+      int start = cb->args[0];
-+      int idx = 0;
-+
-+      swconfig_lock();
-+      list_for_each_entry(dev, &swdevs, dev_list) {
-+              if (++idx <= start)
-+                      continue;
-+              if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid,
-+                              cb->nlh->nlmsg_seq, NLM_F_MULTI,
-+                              dev) < 0)
-+                      break;
-+      }
-+      swconfig_unlock();
-+      cb->args[0] = idx;
-+
-+      return skb->len;
-+}
-+
-+static int
-+swconfig_done(struct netlink_callback *cb)
-+{
-+      return 0;
-+}
-+
-+static struct genl_ops swconfig_ops[] = {
-+      {
-+              .cmd = SWITCH_CMD_LIST_GLOBAL,
-+              .doit = swconfig_list_attrs,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_LIST_VLAN,
-+              .doit = swconfig_list_attrs,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_LIST_PORT,
-+              .doit = swconfig_list_attrs,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_GET_GLOBAL,
-+              .doit = swconfig_get_attr,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_GET_VLAN,
-+              .doit = swconfig_get_attr,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_GET_PORT,
-+              .doit = swconfig_get_attr,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_SET_GLOBAL,
-+              .doit = swconfig_set_attr,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_SET_VLAN,
-+              .doit = swconfig_set_attr,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_SET_PORT,
-+              .doit = swconfig_set_attr,
-+              .policy = switch_policy,
-+      },
-+      {
-+              .cmd = SWITCH_CMD_GET_SWITCH,
-+              .dumpit = swconfig_dump_switches,
-+              .policy = switch_policy,
-+              .done = swconfig_done,
-+      }
-+};
-+
-+#ifdef CONFIG_OF
-+void
-+of_switch_load_portmap(struct switch_dev *dev)
-+{
-+      struct device_node *port;
-+
-+      if (!dev->of_node)
-+              return;
-+
-+      for_each_child_of_node(dev->of_node, port) {
-+              const __be32 *prop;
-+              const char *segment;
-+              int size, phys;
-+
-+              if (!of_device_is_compatible(port, "swconfig,port"))
-+                      continue;
-+
-+              if (of_property_read_string(port, "swconfig,segment", &segment))
-+                      continue;
-+
-+              prop = of_get_property(port, "swconfig,portmap", &size);
-+              if (!prop)
-+                      continue;
-+
-+              if (size != (2 * sizeof(*prop))) {
-+                      pr_err("%s: failed to parse port mapping\n",
-+                                      port->name);
-+                      continue;
-+              }
-+
-+              phys = be32_to_cpup(prop++);
-+              if ((phys < 0) | (phys >= dev->ports)) {
-+                      pr_err("%s: physical port index out of range\n",
-+                                      port->name);
-+                      continue;
-+              }
-+
-+              dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL);
-+              dev->portmap[phys].virt = be32_to_cpup(prop);
-+              pr_debug("Found port: %s, physical: %d, virtual: %d\n",
-+                      segment, phys, dev->portmap[phys].virt);
-+      }
-+}
-+#endif
-+
-+int
-+register_switch(struct switch_dev *dev, struct net_device *netdev)
-+{
-+      struct switch_dev *sdev;
-+      const int max_switches = 8 * sizeof(unsigned long);
-+      unsigned long in_use = 0;
-+      int err;
-+      int i;
-+
-+      INIT_LIST_HEAD(&dev->dev_list);
-+      if (netdev) {
-+              dev->netdev = netdev;
-+              if (!dev->alias)
-+                      dev->alias = netdev->name;
-+      }
-+      BUG_ON(!dev->alias);
-+
-+      if (dev->ports > 0) {
-+              dev->portbuf = kzalloc(sizeof(struct switch_port) *
-+                              dev->ports, GFP_KERNEL);
-+              if (!dev->portbuf)
-+                      return -ENOMEM;
-+              dev->portmap = kzalloc(sizeof(struct switch_portmap) *
-+                              dev->ports, GFP_KERNEL);
-+              if (!dev->portmap) {
-+                      kfree(dev->portbuf);
-+                      return -ENOMEM;
-+              }
-+      }
-+      swconfig_defaults_init(dev);
-+      mutex_init(&dev->sw_mutex);
-+      swconfig_lock();
-+      dev->id = ++swdev_id;
-+
-+      list_for_each_entry(sdev, &swdevs, dev_list) {
-+              if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i))
-+                      continue;
-+              if (i < 0 || i > max_switches)
-+                      continue;
-+
-+              set_bit(i, &in_use);
-+      }
-+      i = find_first_zero_bit(&in_use, max_switches);
-+
-+      if (i == max_switches) {
-+              swconfig_unlock();
-+              return -ENFILE;
-+      }
-+
-+#ifdef CONFIG_OF
-+      if (dev->ports)
-+              of_switch_load_portmap(dev);
-+#endif
-+
-+      /* fill device name */
-+      snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i);
-+
-+      list_add_tail(&dev->dev_list, &swdevs);
-+      swconfig_unlock();
-+
-+      err = swconfig_create_led_trigger(dev);
-+      if (err)
-+              return err;
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(register_switch);
-+
-+void
-+unregister_switch(struct switch_dev *dev)
-+{
-+      swconfig_destroy_led_trigger(dev);
-+      kfree(dev->portbuf);
-+      mutex_lock(&dev->sw_mutex);
-+      swconfig_lock();
-+      list_del(&dev->dev_list);
-+      swconfig_unlock();
-+      mutex_unlock(&dev->sw_mutex);
-+}
-+EXPORT_SYMBOL_GPL(unregister_switch);
-+
-+
-+static int __init
-+swconfig_init(void)
-+{
-+      int err;
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0))
-+      int i;
-+#endif
-+
-+      INIT_LIST_HEAD(&swdevs);
-+      
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0))
-+      err = genl_register_family(&switch_fam);
-+      if (err)
-+              return err;
-+
-+      for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) {
-+              err = genl_register_ops(&switch_fam, &swconfig_ops[i]);
-+              if (err)
-+                      goto unregister;
-+      }
-+      return 0;
-+
-+unregister:
-+      genl_unregister_family(&switch_fam);
-+      return err;
-+#else
-+      err = genl_register_family_with_ops(&switch_fam, swconfig_ops);
-+      if (err)
-+              return err;
-+      return 0;
-+#endif
-+}
-+
-+static void __exit
-+swconfig_exit(void)
-+{
-+      genl_unregister_family(&switch_fam);
-+}
-+
-+module_init(swconfig_init);
-+module_exit(swconfig_exit);
-+
-diff --git a/drivers/net/phy/swconfig_leds.c b/drivers/net/phy/swconfig_leds.c
-new file mode 100644
-index 0000000..abd7bed
---- /dev/null
-+++ b/drivers/net/phy/swconfig_leds.c
-@@ -0,0 +1,354 @@
-+/*
-+ * swconfig_led.c: LED trigger support for the switch configuration API
-+ *
-+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ */
-+
-+#ifdef CONFIG_SWCONFIG_LEDS
-+
-+#include <linux/leds.h>
-+#include <linux/ctype.h>
-+#include <linux/device.h>
-+#include <linux/workqueue.h>
-+
-+#define SWCONFIG_LED_TIMER_INTERVAL   (HZ / 10)
-+#define SWCONFIG_LED_NUM_PORTS                32
-+
-+struct switch_led_trigger {
-+      struct led_trigger trig;
-+      struct switch_dev *swdev;
-+
-+      struct delayed_work sw_led_work;
-+      u32 port_mask;
-+      u32 port_link;
-+      unsigned long port_traffic[SWCONFIG_LED_NUM_PORTS];
-+};
-+
-+struct swconfig_trig_data {
-+      struct led_classdev *led_cdev;
-+      struct switch_dev *swdev;
-+
-+      rwlock_t lock;
-+      u32 port_mask;
-+
-+      bool prev_link;
-+      unsigned long prev_traffic;
-+      enum led_brightness prev_brightness;
-+};
-+
-+static void
-+swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data,
-+                           enum led_brightness brightness)
-+{
-+      led_set_brightness(trig_data->led_cdev, brightness);
-+      trig_data->prev_brightness = brightness;
-+}
-+
-+static void
-+swconfig_trig_update_port_mask(struct led_trigger *trigger)
-+{
-+      struct list_head *entry;
-+      struct switch_led_trigger *sw_trig;
-+      u32 port_mask;
-+
-+      if (!trigger)
-+              return;
-+
-+      sw_trig = (void *) trigger;
-+
-+      port_mask = 0;
-+      read_lock(&trigger->leddev_list_lock);
-+      list_for_each(entry, &trigger->led_cdevs) {
-+              struct led_classdev *led_cdev;
-+              struct swconfig_trig_data *trig_data;
-+
-+              led_cdev = list_entry(entry, struct led_classdev, trig_list);
-+              trig_data = led_cdev->trigger_data;
-+              if (trig_data) {
-+                      read_lock(&trig_data->lock);
-+                      port_mask |= trig_data->port_mask;
-+                      read_unlock(&trig_data->lock);
-+              }
-+      }
-+      read_unlock(&trigger->leddev_list_lock);
-+
-+      sw_trig->port_mask = port_mask;
-+
-+      if (port_mask)
-+              schedule_delayed_work(&sw_trig->sw_led_work,
-+                                    SWCONFIG_LED_TIMER_INTERVAL);
-+      else
-+              cancel_delayed_work_sync(&sw_trig->sw_led_work);
-+}
-+
-+static ssize_t
-+swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr,
-+                            const char *buf, size_t size)
-+{
-+      struct led_classdev *led_cdev = dev_get_drvdata(dev);
-+      struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
-+      unsigned long port_mask;
-+      ssize_t ret = -EINVAL;
-+      char *after;
-+      size_t count;
-+
-+      port_mask = simple_strtoul(buf, &after, 16);
-+      count = after - buf;
-+
-+      if (*after && isspace(*after))
-+              count++;
-+
-+      if (count == size) {
-+              bool changed;
-+
-+              write_lock(&trig_data->lock);
-+
-+              changed = (trig_data->port_mask != port_mask);
-+              if (changed) {
-+                      trig_data->port_mask = port_mask;
-+                      if (port_mask == 0)
-+                              swconfig_trig_set_brightness(trig_data, LED_OFF);
-+              }
-+
-+              write_unlock(&trig_data->lock);
-+
-+              if (changed)
-+                      swconfig_trig_update_port_mask(led_cdev->trigger);
-+
-+              ret = count;
-+      }
-+
-+      return ret;
-+}
-+
-+static ssize_t
-+swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr,
-+                           char *buf)
-+{
-+      struct led_classdev *led_cdev = dev_get_drvdata(dev);
-+      struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
-+
-+      read_lock(&trig_data->lock);
-+      sprintf(buf, "%#x\n", trig_data->port_mask);
-+      read_unlock(&trig_data->lock);
-+
-+      return strlen(buf) + 1;
-+}
-+
-+static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show,
-+                 swconfig_trig_port_mask_store);
-+
-+static void
-+swconfig_trig_activate(struct led_classdev *led_cdev)
-+{
-+      struct switch_led_trigger *sw_trig;
-+      struct swconfig_trig_data *trig_data;
-+      int err;
-+
-+      if (led_cdev->trigger->activate != swconfig_trig_activate)
-+              return;
-+
-+      trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL);
-+      if (!trig_data)
-+              return;
-+
-+      sw_trig = (void *) led_cdev->trigger;
-+
-+      rwlock_init(&trig_data->lock);
-+      trig_data->led_cdev = led_cdev;
-+      trig_data->swdev = sw_trig->swdev;
-+      led_cdev->trigger_data = trig_data;
-+
-+      err = device_create_file(led_cdev->dev, &dev_attr_port_mask);
-+      if (err)
-+              goto err_free;
-+
-+      return;
-+
-+err_free:
-+      led_cdev->trigger_data = NULL;
-+      kfree(trig_data);
-+}
-+
-+static void
-+swconfig_trig_deactivate(struct led_classdev *led_cdev)
-+{
-+      struct swconfig_trig_data *trig_data;
-+
-+      swconfig_trig_update_port_mask(led_cdev->trigger);
-+
-+      trig_data = (void *) led_cdev->trigger_data;
-+      if (trig_data) {
-+              device_remove_file(led_cdev->dev, &dev_attr_port_mask);
-+              kfree(trig_data);
-+      }
-+}
-+
-+static void
-+swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
-+                      struct led_classdev *led_cdev)
-+{
-+      struct swconfig_trig_data *trig_data;
-+      u32 port_mask;
-+      bool link;
-+
-+      trig_data = led_cdev->trigger_data;
-+      if (!trig_data)
-+              return;
-+
-+      read_lock(&trig_data->lock);
-+      port_mask = trig_data->port_mask;
-+      read_unlock(&trig_data->lock);
-+
-+      link = !!(sw_trig->port_link & port_mask);
-+      if (!link) {
-+              if (link != trig_data->prev_link)
-+                      swconfig_trig_set_brightness(trig_data, LED_OFF);
-+      } else {
-+              unsigned long traffic;
-+              int i;
-+
-+              traffic = 0;
-+              for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
-+                      if (port_mask & (1 << i))
-+                              traffic += sw_trig->port_traffic[i];
-+              }
-+
-+              if (trig_data->prev_brightness != LED_FULL)
-+                      swconfig_trig_set_brightness(trig_data, LED_FULL);
-+              else if (traffic != trig_data->prev_traffic)
-+                      swconfig_trig_set_brightness(trig_data, LED_OFF);
-+
-+              trig_data->prev_traffic = traffic;
-+      }
-+
-+      trig_data->prev_link = link;
-+}
-+
-+static void
-+swconfig_trig_update_leds(struct switch_led_trigger *sw_trig)
-+{
-+      struct list_head *entry;
-+      struct led_trigger *trigger;
-+
-+      trigger = &sw_trig->trig;
-+      read_lock(&trigger->leddev_list_lock);
-+      list_for_each(entry, &trigger->led_cdevs) {
-+              struct led_classdev *led_cdev;
-+
-+              led_cdev = list_entry(entry, struct led_classdev, trig_list);
-+              swconfig_trig_led_event(sw_trig, led_cdev);
-+      }
-+      read_unlock(&trigger->leddev_list_lock);
-+}
-+
-+static void
-+swconfig_led_work_func(struct work_struct *work)
-+{
-+      struct switch_led_trigger *sw_trig;
-+      struct switch_dev *swdev;
-+      u32 port_mask;
-+      u32 link;
-+      int i;
-+
-+      sw_trig = container_of(work, struct switch_led_trigger,
-+                             sw_led_work.work);
-+
-+      port_mask = sw_trig->port_mask;
-+      swdev = sw_trig->swdev;
-+
-+      link = 0;
-+      for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
-+              u32 port_bit;
-+
-+              port_bit = BIT(i);
-+              if ((port_mask & port_bit) == 0)
-+                      continue;
-+
-+              if (swdev->ops->get_port_link) {
-+                      struct switch_port_link port_link;
-+
-+                      memset(&port_link, '\0', sizeof(port_link));
-+                      swdev->ops->get_port_link(swdev, i, &port_link);
-+
-+                      if (port_link.link)
-+                              link |= port_bit;
-+              }
-+
-+              if (swdev->ops->get_port_stats) {
-+                      struct switch_port_stats port_stats;
-+
-+                      memset(&port_stats, '\0', sizeof(port_stats));
-+                      swdev->ops->get_port_stats(swdev, i, &port_stats);
-+                      sw_trig->port_traffic[i] = port_stats.tx_bytes +
-+                                                 port_stats.rx_bytes;
-+              }
-+      }
-+
-+      sw_trig->port_link = link;
-+
-+      swconfig_trig_update_leds(sw_trig);
-+
-+      schedule_delayed_work(&sw_trig->sw_led_work,
-+                            SWCONFIG_LED_TIMER_INTERVAL);
-+}
-+
-+static int
-+swconfig_create_led_trigger(struct switch_dev *swdev)
-+{
-+      struct switch_led_trigger *sw_trig;
-+      int err;
-+
-+      if (!swdev->ops->get_port_link)
-+              return 0;
-+
-+      sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL);
-+      if (!sw_trig)
-+              return -ENOMEM;
-+
-+      sw_trig->swdev = swdev;
-+      sw_trig->trig.name = swdev->devname;
-+      sw_trig->trig.activate = swconfig_trig_activate;
-+      sw_trig->trig.deactivate = swconfig_trig_deactivate;
-+
-+      INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func);
-+
-+      err = led_trigger_register(&sw_trig->trig);
-+      if (err)
-+              goto err_free;
-+
-+      swdev->led_trigger = sw_trig;
-+
-+      return 0;
-+
-+err_free:
-+      kfree(sw_trig);
-+      return err;
-+}
-+
-+static void
-+swconfig_destroy_led_trigger(struct switch_dev *swdev)
-+{
-+      struct switch_led_trigger *sw_trig;
-+
-+      sw_trig = swdev->led_trigger;
-+      if (sw_trig) {
-+              cancel_delayed_work_sync(&sw_trig->sw_led_work);
-+              led_trigger_unregister(&sw_trig->trig);
-+              kfree(sw_trig);
-+      }
-+}
-+
-+#else /* SWCONFIG_LEDS */
-+static inline int
-+swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; }
-+
-+static inline void
-+swconfig_destroy_led_trigger(struct switch_dev *swdev) { }
-+#endif /* CONFIG_SWCONFIG_LEDS */
-diff --git a/include/linux/platform_data/b53.h b/include/linux/platform_data/b53.h
-new file mode 100644
-index 0000000..7842741
---- /dev/null
-+++ b/include/linux/platform_data/b53.h
-@@ -0,0 +1,36 @@
-+/*
-+ * B53 platform data
-+ *
-+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#ifndef __B53_H
-+#define __B53_H
-+
-+#include <linux/kernel.h>
-+
-+struct b53_platform_data {
-+      u32 chip_id;
-+      u16 enabled_ports;
-+
-+      /* allow to specify an ethX alias */
-+      const char *alias;
-+
-+      /* only used by MMAP'd driver */
-+      unsigned big_endian:1;
-+      void __iomem *regs;
-+};
-+
-+#endif
-diff --git a/include/linux/switch.h b/include/linux/switch.h
-new file mode 100644
-index 0000000..b53431e
---- /dev/null
-+++ b/include/linux/switch.h
-@@ -0,0 +1,167 @@
-+/*
-+ * switch.h: Switch configuration API
-+ *
-+ * 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
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+#ifndef _LINUX_SWITCH_H
-+#define _LINUX_SWITCH_H
-+
-+#include <net/genetlink.h>
-+#include <uapi/linux/switch.h>
-+
-+struct switch_dev;
-+struct switch_op;
-+struct switch_val;
-+struct switch_attr;
-+struct switch_attrlist;
-+struct switch_led_trigger;
-+
-+int register_switch(struct switch_dev *dev, struct net_device *netdev);
-+void unregister_switch(struct switch_dev *dev);
-+
-+/**
-+ * struct switch_attrlist - attribute list
-+ *
-+ * @n_attr: number of attributes
-+ * @attr: pointer to the attributes array
-+ */
-+struct switch_attrlist {
-+      int n_attr;
-+      const struct switch_attr *attr;
-+};
-+
-+enum switch_port_speed {
-+      SWITCH_PORT_SPEED_UNKNOWN = 0,
-+      SWITCH_PORT_SPEED_10 = 10,
-+      SWITCH_PORT_SPEED_100 = 100,
-+      SWITCH_PORT_SPEED_1000 = 1000,
-+};
-+
-+struct switch_port_link {
-+      bool link;
-+      bool duplex;
-+      bool aneg;
-+      bool tx_flow;
-+      bool rx_flow;
-+      enum switch_port_speed speed;
-+};
-+
-+struct switch_port_stats {
-+      unsigned long tx_bytes;
-+      unsigned long rx_bytes;
-+};
-+
-+/**
-+ * struct switch_dev_ops - switch driver operations
-+ *
-+ * @attr_global: global switch attribute list
-+ * @attr_port: port attribute list
-+ * @attr_vlan: vlan attribute list
-+ *
-+ * Callbacks:
-+ *
-+ * @get_vlan_ports: read the port list of a VLAN
-+ * @set_vlan_ports: set the port list of a VLAN
-+ *
-+ * @get_port_pvid: get the primary VLAN ID of a port
-+ * @set_port_pvid: set the primary VLAN ID of a port
-+ *
-+ * @apply_config: apply all changed settings to the switch
-+ * @reset_switch: resetting the switch
-+ */
-+struct switch_dev_ops {
-+      struct switch_attrlist attr_global, attr_port, attr_vlan;
-+
-+      int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
-+      int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
-+
-+      int (*get_port_pvid)(struct switch_dev *dev, int port, int *val);
-+      int (*set_port_pvid)(struct switch_dev *dev, int port, int val);
-+
-+      int (*apply_config)(struct switch_dev *dev);
-+      int (*reset_switch)(struct switch_dev *dev);
-+
-+      int (*get_port_link)(struct switch_dev *dev, int port,
-+                           struct switch_port_link *link);
-+      int (*get_port_stats)(struct switch_dev *dev, int port,
-+                            struct switch_port_stats *stats);
-+};
-+
-+struct switch_dev {
-+      struct device_node *of_node;
-+      const struct switch_dev_ops *ops;
-+      /* will be automatically filled */
-+      char devname[IFNAMSIZ];
-+
-+      const char *name;
-+      /* NB: either alias or netdev must be set */
-+      const char *alias;
-+      struct net_device *netdev;
-+
-+      int ports;
-+      int vlans;
-+      int cpu_port;
-+
-+      /* the following fields are internal for swconfig */
-+      int id;
-+      struct list_head dev_list;
-+      unsigned long def_global, def_port, def_vlan;
-+
-+      struct mutex sw_mutex;
-+      struct switch_port *portbuf;
-+      struct switch_portmap *portmap;
-+
-+      char buf[128];
-+
-+#ifdef CONFIG_SWCONFIG_LEDS
-+      struct switch_led_trigger *led_trigger;
-+#endif
-+};
-+
-+struct switch_port {
-+      u32 id;
-+      u32 flags;
-+};
-+
-+struct switch_portmap {
-+      u32 virt;
-+      const char *s;
-+};
-+
-+struct switch_val {
-+      const struct switch_attr *attr;
-+      int port_vlan;
-+      int len;
-+      union {
-+              const char *s;
-+              u32 i;
-+              struct switch_port *ports;
-+      } value;
-+};
-+
-+struct switch_attr {
-+      int disabled;
-+      int type;
-+      const char *name;
-+      const char *description;
-+
-+      int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
-+      int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
-+
-+      /* for driver internal use */
-+      int id;
-+      int ofs;
-+      int max;
-+};
-+
-+#endif /* _LINUX_SWITCH_H */
-diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
-index 3ce25b5..b9565df 100644
---- a/include/uapi/linux/Kbuild
-+++ b/include/uapi/linux/Kbuild
-@@ -365,6 +365,7 @@ header-y += stddef.h
- header-y += string.h
- header-y += suspend_ioctls.h
- header-y += swab.h
-+header-y += switch.h
- header-y += synclink.h
- header-y += sysctl.h
- header-y += sysinfo.h
-diff --git a/include/uapi/linux/switch.h b/include/uapi/linux/switch.h
-new file mode 100644
-index 0000000..a59b239
---- /dev/null
-+++ b/include/uapi/linux/switch.h
-@@ -0,0 +1,103 @@
-+/*
-+ * switch.h: Switch configuration API
-+ *
-+ * 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
-+ * as published by the Free Software Foundation; either version 2
-+ * of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef _UAPI_LINUX_SWITCH_H
-+#define _UAPI_LINUX_SWITCH_H
-+
-+#include <linux/types.h>
-+#include <linux/netdevice.h>
-+#include <linux/netlink.h>
-+#include <linux/genetlink.h>
-+#ifndef __KERNEL__
-+#include <netlink/netlink.h>
-+#include <netlink/genl/genl.h>
-+#include <netlink/genl/ctrl.h>
-+#endif
-+
-+/* main attributes */
-+enum {
-+      SWITCH_ATTR_UNSPEC,
-+      /* global */
-+      SWITCH_ATTR_TYPE,
-+      /* device */
-+      SWITCH_ATTR_ID,
-+      SWITCH_ATTR_DEV_NAME,
-+      SWITCH_ATTR_ALIAS,
-+      SWITCH_ATTR_NAME,
-+      SWITCH_ATTR_VLANS,
-+      SWITCH_ATTR_PORTS,
-+      SWITCH_ATTR_PORTMAP,
-+      SWITCH_ATTR_CPU_PORT,
-+      /* attributes */
-+      SWITCH_ATTR_OP_ID,
-+      SWITCH_ATTR_OP_TYPE,
-+      SWITCH_ATTR_OP_NAME,
-+      SWITCH_ATTR_OP_PORT,
-+      SWITCH_ATTR_OP_VLAN,
-+      SWITCH_ATTR_OP_VALUE_INT,
-+      SWITCH_ATTR_OP_VALUE_STR,
-+      SWITCH_ATTR_OP_VALUE_PORTS,
-+      SWITCH_ATTR_OP_DESCRIPTION,
-+      /* port lists */
-+      SWITCH_ATTR_PORT,
-+      SWITCH_ATTR_MAX
-+};
-+
-+enum {
-+      /* port map */
-+      SWITCH_PORTMAP_PORTS,
-+      SWITCH_PORTMAP_SEGMENT,
-+      SWITCH_PORTMAP_VIRT,
-+      SWITCH_PORTMAP_MAX
-+};
-+
-+/* commands */
-+enum {
-+      SWITCH_CMD_UNSPEC,
-+      SWITCH_CMD_GET_SWITCH,
-+      SWITCH_CMD_NEW_ATTR,
-+      SWITCH_CMD_LIST_GLOBAL,
-+      SWITCH_CMD_GET_GLOBAL,
-+      SWITCH_CMD_SET_GLOBAL,
-+      SWITCH_CMD_LIST_PORT,
-+      SWITCH_CMD_GET_PORT,
-+      SWITCH_CMD_SET_PORT,
-+      SWITCH_CMD_LIST_VLAN,
-+      SWITCH_CMD_GET_VLAN,
-+      SWITCH_CMD_SET_VLAN
-+};
-+
-+/* data types */
-+enum switch_val_type {
-+      SWITCH_TYPE_UNSPEC,
-+      SWITCH_TYPE_INT,
-+      SWITCH_TYPE_STRING,
-+      SWITCH_TYPE_PORTS,
-+      SWITCH_TYPE_NOVAL,
-+};
-+
-+/* port nested attributes */
-+enum {
-+      SWITCH_PORT_UNSPEC,
-+      SWITCH_PORT_ID,
-+      SWITCH_PORT_FLAG_TAGGED,
-+      SWITCH_PORT_ATTR_MAX
-+};
-+
-+#define SWITCH_ATTR_DEFAULTS_OFFSET   0x1000
-+
-+
-+#endif /* _UAPI_LINUX_SWITCH_H */