]> git.ipfire.org Git - people/arne_f/ipfire-2.x.git/commitdiff
Merge remote-tracking branch 'ummeegge/mtr'
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 28 Jan 2015 21:42:28 +0000 (22:42 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 28 Jan 2015 21:42:28 +0000 (22:42 +0100)
47 files changed:
config/etc/modprobe.d/btmrvl_sdio.conf [new file with mode: 0644]
config/firewall/rules.pl
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/initscripts
config/rootfiles/common/armv5tel/linux-kirkwood
config/rootfiles/common/armv5tel/linux-multi
config/rootfiles/common/armv5tel/linux-rpi
config/rootfiles/common/armv5tel/swconfig [new file with mode: 0644]
config/rootfiles/common/armv5tel/util-linux
config/rootfiles/common/crda
config/rootfiles/common/i586/util-linux
config/rootfiles/common/stage2
config/rootfiles/core/86/exclude
config/rootfiles/core/86/filelists/armv5tel/swconfig [new symlink]
config/rootfiles/core/86/filelists/files
config/rootfiles/core/86/update.sh
html/cgi-bin/wlanap.cgi
lfs/backports
lfs/glibc
lfs/hostapd
lfs/initscripts
lfs/linux
lfs/strongswan
lfs/swconfig [new file with mode: 0644]
make.sh
src/initscripts/init.d/collectd
src/initscripts/init.d/hostapd
src/initscripts/init.d/leds
src/initscripts/init.d/swconfig [new file with mode: 0644]
src/installer/main.c
src/patches/glibc/glibc-rh1019916.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1027101.patch [moved from src/patches/glibc/glibc-rh1091162.patch with 100% similarity]
src/patches/glibc/glibc-rh1027261.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1032628.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1044628.patch [moved from src/patches/glibc/glibc-rh1098050.patch with 100% similarity]
src/patches/glibc/glibc-rh1111460.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1139571.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1154563.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1170121.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh1183533.patch [new file with mode: 0644]
src/patches/glibc/glibc-rh995972.patch [new file with mode: 0644]
src/patches/linux-3.14.x-lamobo-r1.patch [new file with mode: 0644]
src/patches/strongswan-5.1.2-5.2.1_modp_custom.patch [new file with mode: 0644]

diff --git a/config/etc/modprobe.d/btmrvl_sdio.conf b/config/etc/modprobe.d/btmrvl_sdio.conf
new file mode 100644 (file)
index 0000000..66cd021
--- /dev/null
@@ -0,0 +1,2 @@
+# seems to crash often
+blacklist btmrvl_sdio
index a475e2d60ea7cb880746471ea8623e10cb64ffbd..97b8897af87bba6f84ec2e961e3bbb62849a17ef 100755 (executable)
@@ -368,20 +368,12 @@ sub buildrules {
                                                push(@source_options, ("-s", $source));
                                        }
 
-                                       if ($source_intf) {
-                                               push(@source_options, ("-i", $source_intf));
-                                       }
-
                                        # Prepare destination options.
                                        my @destination_options = ();
                                        if ($destination) {
                                                push(@destination_options, ("-d", $destination));
                                        }
 
-                                       if ($destination_intf) {
-                                               push(@destination_options, ("-o", $destination_intf));
-                                       }
-
                                        # Add time constraint options.
                                        push(@options, @time_options);
 
@@ -476,6 +468,17 @@ sub buildrules {
                                                }
                                        }
 
+                                       # Add source and destination interface to the filter rules.
+                                       # These are supposed to help filtering forged packets that originate
+                                       # from BLUE with an IP address from GREEN for instance.
+                                       if ($source_intf) {
+                                               push(@source_options, ("-i", $source_intf));
+                                       }
+
+                                       if ($destination_intf) {
+                                               push(@destination_options, ("-o", $destination_intf));
+                                       }
+
                                        push(@options, @source_options);
                                        push(@options, @destination_options);
 
index fbfc05c75688ced5d120a60f40351c6d4f8b96d3..ff09320c231584f64730fee513f7cb8f30f7c369 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.22 Kernel Configuration
+# Linux/arm 3.14.27 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -3393,7 +3393,7 @@ CONFIG_SMS_SIANO_RC=y
 #
 CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
 CONFIG_MEDIA_ATTACH=y
-CONFIG_VIDEO_IR_I2C=y
+CONFIG_VIDEO_IR_I2C=m
 
 #
 # Audio decoders, processors and mixers
@@ -3480,24 +3480,24 @@ CONFIG_SOC_CAMERA_OV9640=m
 CONFIG_SOC_CAMERA_OV9740=m
 CONFIG_SOC_CAMERA_RJ54N1=m
 CONFIG_SOC_CAMERA_TW9910=m
-CONFIG_MEDIA_TUNER=y
-CONFIG_MEDIA_TUNER_SIMPLE=y
-CONFIG_MEDIA_TUNER_TDA8290=y
-CONFIG_MEDIA_TUNER_TDA827X=y
-CONFIG_MEDIA_TUNER_TDA18271=y
-CONFIG_MEDIA_TUNER_TDA9887=y
-CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER=m
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_MT20XX=m
 CONFIG_MEDIA_TUNER_MT2060=m
 CONFIG_MEDIA_TUNER_MT2063=m
 CONFIG_MEDIA_TUNER_MT2266=m
 CONFIG_MEDIA_TUNER_MT2131=m
 CONFIG_MEDIA_TUNER_QT1010=m
-CONFIG_MEDIA_TUNER_XC2028=y
-CONFIG_MEDIA_TUNER_XC5000=y
-CONFIG_MEDIA_TUNER_XC4000=y
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_XC4000=m
 CONFIG_MEDIA_TUNER_MXL5005S=m
 CONFIG_MEDIA_TUNER_MXL5007T=m
-CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_MEDIA_TUNER_MC44S803=m
 CONFIG_MEDIA_TUNER_MAX2165=m
 CONFIG_MEDIA_TUNER_TDA18218=m
 CONFIG_MEDIA_TUNER_FC0011=m
index 8249d2c8dec08f5a3eb684afa4ed96bf908d0695..6c387b305e9b9e75dc7c45d7cc20253058d68f98 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.25 Kernel Configuration
+# Linux/arm 3.14.29 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_MIGHT_HAVE_PCI=y
@@ -2053,8 +2053,8 @@ CONFIG_IP1000=m
 CONFIG_JME=m
 CONFIG_NET_VENDOR_MARVELL=y
 CONFIG_MV643XX_ETH=m
-CONFIG_MVMDIO=m
-CONFIG_MVNETA=m
+CONFIG_MVMDIO=y
+CONFIG_MVNETA=y
 CONFIG_SKGE=m
 # CONFIG_SKGE_DEBUG is not set
 CONFIG_SKGE_GENESIS=y
@@ -2155,6 +2155,8 @@ CONFIG_XILINX_EMACLITE=m
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 CONFIG_PHYLIB=y
+CONFIG_SWCONFIG=m
+# CONFIG_SWCONFIG_LEDS is not set
 
 #
 # MII PHY device drivers
@@ -2178,11 +2180,16 @@ CONFIG_LSI_ET1011C_PHY=m
 CONFIG_MICREL_PHY=m
 CONFIG_FIXED_PHY=y
 CONFIG_MDIO_BITBANG=m
-# CONFIG_MDIO_GPIO is not set
+CONFIG_MDIO_GPIO=m
 CONFIG_MDIO_SUN4I=m
 CONFIG_MDIO_BUS_MUX=m
 CONFIG_MDIO_BUS_MUX_GPIO=m
 CONFIG_MDIO_BUS_MUX_MMIOREG=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
@@ -3348,10 +3355,10 @@ CONFIG_VIDEO_V4L2=m
 # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
 CONFIG_VIDEO_TUNER=m
 CONFIG_V4L2_MEM2MEM_DEV=m
-CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_GEN=m
 CONFIG_VIDEOBUF_DMA_SG=m
 CONFIG_VIDEOBUF_VMALLOC=m
-CONFIG_VIDEOBUF_DMA_CONTIG=y
+CONFIG_VIDEOBUF_DMA_CONTIG=m
 CONFIG_VIDEOBUF_DVB=m
 CONFIG_VIDEOBUF2_CORE=m
 CONFIG_VIDEOBUF2_MEMOPS=m
@@ -3603,9 +3610,11 @@ CONFIG_V4L_PLATFORM_DRIVERS=y
 # CONFIG_VIDEO_CAFE_CCIC is not set
 # CONFIG_VIDEO_DM6446_CCDC is not set
 CONFIG_VIDEO_OMAP2_VOUT_VRFB=y
-CONFIG_VIDEO_OMAP2_VOUT=y
+CONFIG_VIDEO_OMAP2_VOUT=m
 CONFIG_VIDEO_TIMBERDALE=m
 CONFIG_SOC_CAMERA=m
+CONFIG_SOC_CAMERA_SCALE_CROP=m
+CONFIG_SOC_CAMERA_PLATFORM=m
 CONFIG_VIDEO_MX3=m
 CONFIG_VIDEO_RCAR_VIN=m
 # CONFIG_VIDEO_SH_MOBILE_CSI2 is not set
@@ -3649,7 +3658,7 @@ CONFIG_SMS_SIANO_RC=y
 #
 CONFIG_MEDIA_SUBDRV_AUTOSELECT=y
 CONFIG_MEDIA_ATTACH=y
-CONFIG_VIDEO_IR_I2C=y
+CONFIG_VIDEO_IR_I2C=m
 
 #
 # Audio decoders, processors and mixers
@@ -3735,24 +3744,24 @@ CONFIG_SOC_CAMERA_OV9640=m
 CONFIG_SOC_CAMERA_OV9740=m
 CONFIG_SOC_CAMERA_RJ54N1=m
 CONFIG_SOC_CAMERA_TW9910=m
-CONFIG_MEDIA_TUNER=y
-CONFIG_MEDIA_TUNER_SIMPLE=y
-CONFIG_MEDIA_TUNER_TDA8290=y
-CONFIG_MEDIA_TUNER_TDA827X=y
-CONFIG_MEDIA_TUNER_TDA18271=y
-CONFIG_MEDIA_TUNER_TDA9887=y
-CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER=m
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_MT20XX=m
 CONFIG_MEDIA_TUNER_MT2060=m
 CONFIG_MEDIA_TUNER_MT2063=m
 CONFIG_MEDIA_TUNER_MT2266=m
 CONFIG_MEDIA_TUNER_MT2131=m
 CONFIG_MEDIA_TUNER_QT1010=m
-CONFIG_MEDIA_TUNER_XC2028=y
-CONFIG_MEDIA_TUNER_XC5000=y
-CONFIG_MEDIA_TUNER_XC4000=y
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_XC4000=m
 CONFIG_MEDIA_TUNER_MXL5005S=m
 CONFIG_MEDIA_TUNER_MXL5007T=m
-CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_MEDIA_TUNER_MC44S803=m
 CONFIG_MEDIA_TUNER_MAX2165=m
 CONFIG_MEDIA_TUNER_TDA18218=m
 CONFIG_MEDIA_TUNER_FC0011=m
@@ -4850,7 +4859,7 @@ CONFIG_RTC_DRV_PL030=m
 CONFIG_RTC_DRV_PL031=m
 CONFIG_RTC_DRV_VT8500=m
 CONFIG_RTC_DRV_SUNXI=y
-CONFIG_RTC_DRV_MV=m
+CONFIG_RTC_DRV_MV=y
 CONFIG_RTC_DRV_MXC=m
 CONFIG_RTC_DRV_SNVS=m
 CONFIG_RTC_DRV_MOXART=m
index b02167d311b534d2a5fbc96b4ca1760b3e5c4f64..7aef006a0e7a101d0e134582f5d5779710783926 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.14.22 Kernel Configuration
+# Linux/arm 3.14.27 Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -1325,7 +1325,7 @@ CONFIG_DM_DELAY=m
 # CONFIG_DM_SWITCH is not set
 # CONFIG_TARGET_CORE is not set
 CONFIG_NETDEVICES=y
-CONFIG_MII=y
+CONFIG_MII=m
 CONFIG_NET_CORE=y
 CONFIG_BONDING=m
 CONFIG_DUMMY=m
@@ -1465,7 +1465,7 @@ CONFIG_USB_NET_DM9601=m
 CONFIG_USB_NET_SR9700=m
 CONFIG_USB_NET_SR9800=m
 CONFIG_USB_NET_SMSC75XX=m
-CONFIG_USB_NET_SMSC95XX=y
+CONFIG_USB_NET_SMSC95XX=m
 CONFIG_USB_NET_GL620A=m
 CONFIG_USB_NET_NET1080=m
 CONFIG_USB_NET_PLUSB=m
index 5869b8818b7d9a72d247bcafe4064995fc5af4ff..967ae6698ed9c3c735cba9d57b73609a3a6b43e6 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.14.22 Kernel Configuration
+# Linux/x86 3.14.27 Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -724,6 +724,7 @@ CONFIG_HAVE_AOUT=y
 CONFIG_BINFMT_MISC=y
 CONFIG_COREDUMP=y
 CONFIG_HAVE_ATOMIC_IOMAP=y
+CONFIG_IOSF_MBI=m
 CONFIG_NET=y
 
 #
index 54cfb0642b3a130b4ef1dad6ff12d42e66a1306b..be7eb4aa26008f6cf00526053dee8d90350490ef 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.14.22 Kernel Configuration
+# Linux/x86 3.14.27 Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -738,6 +738,7 @@ CONFIG_HAVE_AOUT=y
 CONFIG_BINFMT_MISC=y
 CONFIG_COREDUMP=y
 CONFIG_HAVE_ATOMIC_IOMAP=y
+CONFIG_IOSF_MBI=m
 CONFIG_NET=y
 
 #
@@ -3832,7 +3833,6 @@ CONFIG_DVB_TDA826X=m
 CONFIG_DVB_TUA6100=m
 CONFIG_DVB_CX24116=m
 CONFIG_DVB_CX24117=m
-CONFIG_DVB_M88DC2800=m
 CONFIG_DVB_SI21XX=m
 CONFIG_DVB_TS2020=m
 CONFIG_DVB_DS3000=m
@@ -3914,6 +3914,8 @@ CONFIG_DVB_A8293=m
 CONFIG_DVB_LGS8GXX=m
 CONFIG_DVB_ATBM8830=m
 CONFIG_DVB_TDA665x=m
+CONFIG_DVB_DVBSKY_M88DS3103=m
+CONFIG_DVB_M88DC2800=m
 CONFIG_DVB_IX2505V=m
 CONFIG_DVB_IT913X_FE=m
 CONFIG_DVB_M88RS2000=m
index 980441599ec703d158feed8e74cbddf3b5c33077..60ef0ef19c9089375a75ee1790ec8319d0f0c6a2 100644 (file)
@@ -117,6 +117,7 @@ etc/rc.d/init.d/sshd
 etc/rc.d/init.d/static-routes
 #etc/rc.d/init.d/stunnel
 etc/rc.d/init.d/swap
+etc/rc.d/init.d/swconfig
 etc/rc.d/init.d/sysctl
 etc/rc.d/init.d/sysklogd
 etc/rc.d/init.d/teamspeak
@@ -223,6 +224,7 @@ etc/rc.d/rcsysinit.d/S45udev_retry
 etc/rc.d/rcsysinit.d/S50cleanfs
 etc/rc.d/rcsysinit.d/S60setclock
 etc/rc.d/rcsysinit.d/S70console
+etc/rc.d/rcsysinit.d/S73swconfig
 etc/rc.d/rcsysinit.d/S75firstsetup
 etc/rc.d/rcsysinit.d/S80localnet
 etc/rc.d/rcsysinit.d/S85firewall
index 50ac43471b66c588c34a86d798a9633c931f0bb5..f5ae58567f7b66fe8b9fb9efdb90c7e271c7bfa6 100644 (file)
@@ -548,6 +548,8 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/common/siano/smsdvb.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/common/siano/smsmdtv.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/common/tveeprom.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/dvb-core
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/dvb-core/dvb-core.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/dvb-frontends
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/dvb-frontends/a8293.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/dvb-frontends/af9013.ko
@@ -649,6 +651,7 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/cs53l32a.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/cx25840
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/cx25840/cx25840.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/ir-kbd-i2c.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/m52790.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/msp3400.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/mt9v011.ko
@@ -684,6 +687,7 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/vp27smpx.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/wm8739.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/i2c/wm8775.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/media.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/pci
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/pci/b2c2
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/pci/b2c2/b2c2-flexcop-pci.ko
@@ -878,6 +882,7 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/rc/keymaps/rc-winfast.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/rc/lirc_dev.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/rc/mceusb.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/rc/rc-core.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/rc/rc-loopback.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/rc/redrat3.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/rc/streamzap.ko
@@ -890,8 +895,10 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/fc2580.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/m88ts2022.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/max2165.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/mc44s803.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/mt2060.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/mt2063.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/mt20xx.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/mt2131.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/mt2266.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/mxl5005s.ko
@@ -900,8 +907,17 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/r820t.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tda18212.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tda18218.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tda18271.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tda827x.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tda8290.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tda9887.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tua9001.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tuner-simple.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tuner-types.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tuner-xc2028.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/tuner_it913x.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/xc4000.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/tuners/xc5000.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/usb
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/usb/au0828
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/usb/au0828/au0828.ko
@@ -1049,6 +1065,8 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/usb/zr364xx/zr364xx.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/tuner.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/v4l2-common.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/v4l2-dv-timings.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/v4l2-mem2mem.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/videobuf-core.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/videobuf-dma-contig.ko
@@ -1059,6 +1077,7 @@ lib/modules/KVER-ipfire-kirkwood
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/videobuf2-dma-contig.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/videobuf2-memops.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/videobuf2-vmalloc.ko
+#lib/modules/KVER-ipfire-kirkwood/kernel/drivers/media/v4l2-core/videodev.ko
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/memstick
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/memstick/core
 #lib/modules/KVER-ipfire-kirkwood/kernel/drivers/memstick/core/memstick.ko
index eee6ad22ce6a38b006cbcfcd663cb1f260f7926a..1313d76a9fdca763b7c44346d5686f71a137979c 100644 (file)
@@ -596,6 +596,8 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/common/siano/smsdvb.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/common/siano/smsmdtv.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/common/tveeprom.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/dvb-core
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/dvb-core/dvb-core.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/dvb-frontends
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/dvb-frontends/a8293.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/dvb-frontends/af9013.ko
@@ -694,6 +696,7 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/cs53l32a.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/cx25840
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/cx25840/cx25840.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/ir-kbd-i2c.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/m52790.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/msp3400.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/mt9v011.ko
@@ -728,6 +731,7 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/vp27smpx.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/wm8739.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/i2c/wm8775.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/media.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/pci
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/pci/b2c2
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/pci/b2c2/b2c2-flexcop-pci.ko
@@ -793,6 +797,8 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/pci/ttpci/ttpci-eeprom.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/platform
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/platform/m2m-deinterlace.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/platform/omap
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/platform/omap/omap-vout.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/platform/sh_veu.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/platform/soc_camera
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/platform/soc_camera/mx3_camera.ko
@@ -925,6 +931,7 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/rc/keymaps/rc-winfast.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/rc/lirc_dev.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/rc/mceusb.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/rc/rc-core.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/rc/rc-loopback.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/rc/redrat3.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/rc/streamzap.ko
@@ -938,8 +945,10 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/fc2580.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/m88ts2022.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/max2165.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/mc44s803.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/mt2060.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/mt2063.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/mt20xx.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/mt2131.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/mt2266.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/mxl5005s.ko
@@ -948,8 +957,17 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/r820t.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tda18212.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tda18218.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tda18271.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tda827x.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tda8290.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tda9887.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tua9001.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tuner-simple.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tuner-types.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tuner-xc2028.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/tuner_it913x.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/xc4000.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/tuners/xc5000.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/usb
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/usb/au0828
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/usb/au0828/au0828.ko
@@ -1092,7 +1110,11 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/usb/zr364xx/zr364xx.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/tuner.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/v4l2-common.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/v4l2-dv-timings.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/v4l2-mem2mem.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf-core.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf-dma-contig.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf-dma-sg.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf-dvb.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf-vmalloc.ko
@@ -1100,6 +1122,7 @@ lib/modules/KVER-ipfire-multi
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf2-dma-contig.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf2-memops.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videobuf2-vmalloc.ko
+#lib/modules/KVER-ipfire-multi/kernel/drivers/media/v4l2-core/videodev.ko
 #lib/modules/KVER-ipfire-multi/kernel/drivers/memstick
 #lib/modules/KVER-ipfire-multi/kernel/drivers/memstick/core
 #lib/modules/KVER-ipfire-multi/kernel/drivers/memstick/core/memstick.ko
index ee74ac3452c7fb4c672ea8de6f4d08f2e11b9df7..dbde8c05b83e1e61a91fc2033c354600c8e18e79 100644 (file)
@@ -778,6 +778,7 @@ lib/modules/KVER-ipfire-rpi
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/ifb.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/imq.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/macvlan.ko
+#lib/modules/KVER-ipfire-rpi/kernel/drivers/net/mii.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/netconsole.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/phy
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/phy/libphy.ko
@@ -824,8 +825,10 @@ lib/modules/KVER-ipfire-rpi
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/rtl8150.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/sierra_net.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/smsc75xx.ko
+#lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/smsc95xx.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/sr9700.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/sr9800.ko
+#lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/usbnet.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/usb/zaurus.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/veth.ko
 #lib/modules/KVER-ipfire-rpi/kernel/drivers/net/wireless
diff --git a/config/rootfiles/common/armv5tel/swconfig b/config/rootfiles/common/armv5tel/swconfig
new file mode 100644 (file)
index 0000000..720791e
--- /dev/null
@@ -0,0 +1 @@
+usr/bin/swconfig
index 0f364095085cba5a61df472ba657a401b4468b5c..2675dd0a8fb4b15ec6a35c8f3675d212dd636655 100644 (file)
@@ -74,7 +74,7 @@ usr/bin/renice
 #usr/bin/setarch
 usr/bin/setsid
 #usr/bin/setterm
-#usr/bin/tailf
+usr/bin/tailf
 #usr/bin/taskset
 #usr/bin/ul
 #usr/bin/unshare
index 74f0850ed215edc4775e0355625cdaae1fb6957c..1e6f6025a496c305bc67997f411c5d8846482e15 100644 (file)
@@ -1,8 +1,8 @@
 lib/udev/rules.d/85-regulatory.rules
 #root/.python-eggs
-#root/.python-eggs/M2Crypto-0.21.1-py2.7-linux-i586.egg-tmp
-#root/.python-eggs/M2Crypto-0.21.1-py2.7-linux-i586.egg-tmp/M2Crypto
-#root/.python-eggs/M2Crypto-0.21.1-py2.7-linux-i586.egg-tmp/M2Crypto/__m2crypto.so
+#root/.python-eggs/M2Crypto-0.21.1-py2.7-linux-MACHINE.egg-tmp
+#root/.python-eggs/M2Crypto-0.21.1-py2.7-linux-MACHINE.egg-tmp/M2Crypto
+#root/.python-eggs/M2Crypto-0.21.1-py2.7-linux-MACHINE.egg-tmp/M2Crypto/__m2crypto.so
 sbin/crda
 sbin/regdbdump
 #usr/include/reglib
index 34c87f27694e6a69727a65ae40588d53c9368cc1..9b8d484e3c565590806e09038e8a68a9eafc7cf9 100644 (file)
@@ -75,7 +75,7 @@ usr/bin/renice
 #usr/bin/setarch
 usr/bin/setsid
 #usr/bin/setterm
-#usr/bin/tailf
+usr/bin/tailf
 #usr/bin/taskset
 #usr/bin/ul
 #usr/bin/unshare
index 9a4d8ed975c4feafe1dfa0e2dd2a409ad8b2bf96..323f9780d7b3e767bc1091bd64df5a826c015f89 100644 (file)
@@ -20,6 +20,7 @@ etc/ld.so.conf
 etc/logrotate.conf
 etc/mime.types
 etc/modprobe.d
+etc/modprobe.d/btmrvl_sdio.conf
 etc/modprobe.d/cfg80211.conf
 etc/modprobe.d/pcspeaker.conf
 etc/modules.conf
index 18e9b4d2433cbceb33fa5ac82618577040e4f66e..6bc39ce506dea1ab28269a1b88566a182d715030 100644 (file)
@@ -14,6 +14,7 @@ etc/sysconfig/firewall.local
 etc/sysconfig/rc.local
 etc/udev/rules.d/30-persistent-network.rules
 srv/web/ipfire/html/proxy.pac
+var/ipfire/time
 var/ipfire/ovpn
 var/log/cache
 var/state/dhcp/dhcpd.leases
diff --git a/config/rootfiles/core/86/filelists/armv5tel/swconfig b/config/rootfiles/core/86/filelists/armv5tel/swconfig
new file mode 120000 (symlink)
index 0000000..e5606ed
--- /dev/null
@@ -0,0 +1 @@
+../../../../common/armv5tel/swconfig
\ No newline at end of file
index dcdb65c9607c9afdc5665068d9239485f2170668..3745701e5dc65b507ebea8f3439b5dc4ec54cc97 100644 (file)
@@ -1,5 +1,8 @@
 etc/system-release
 etc/issue
+etc/modprobe.d/btmrvl_sdio.conf
+etc/rc.d/init.d/collectd
+etc/rc.d/init.d/leds
 opt/pakfire/etc/pakfire.conf
 usr/lib/firewall/rules.pl
 usr/local/bin/update-bootloader
index bdb96fc6e475c48cb6bc9f1467b28d1a064957d7..bb7453f5ce713921d53d39de2cd6651e9c310310 100644 (file)
 . /opt/pakfire/lib/functions.sh
 /usr/local/bin/backupctrl exclude >/dev/null 2>&1
 
-function add_to_backup ()
-{
-       # Add path to ROOTFILES but remove old entries to prevent double
-       # files in the tar
-       grep -v "^$1" /opt/pakfire/tmp/ROOTFILES > /opt/pakfire/tmp/ROOTFILES.tmp
-       mv /opt/pakfire/tmp/ROOTFILES.tmp /opt/pakfire/tmp/ROOTFILES
-       echo $1 >> /opt/pakfire/tmp/ROOTFILES
-}
-
 #
 # Remove old core updates from pakfire cache to save space...
 core=86
@@ -65,23 +56,6 @@ esac
 #
 KVER="xxxKVERxxx"
 
-#
-# check if we the backup file already exist
-if [ -e /var/ipfire/backup/core-upgrade${core}_${KVER}.tar.xz ]; then
-    echo Moving backup to backup-old ...
-    mv -f /var/ipfire/backup/core-upgrade${core}_${KVER}.tar.xz \
-       /var/ipfire/backup/core-upgrade${core}_${KVER}-old.tar.xz
-fi
-echo First we made a backup of all files that was inside of the
-echo update archive. This may take a while ...
-# Add some files that are not in the package to backup
-add_to_backup lib/modules
-add_to_backup boot
-
-# Backup the files
-tar cJvf /var/ipfire/backup/core-upgrade${core}_${KVER}.tar.xz \
-    -C / -T /opt/pakfire/tmp/ROOTFILES --exclude='#*' --exclude='/var/cache' > /dev/null 2>&1
-
 # Check diskspace on root
 ROOTSPACE=`df / -Pk | sed "s| * | |g" | cut -d" " -f4 | tail -n 1`
 
@@ -232,7 +206,7 @@ echo '/opt/pakfire/pakfire update -y --force'             >> /tmp/pak_update
 echo '/opt/pakfire/pakfire upgrade -y'                    >> /tmp/pak_update
 echo '/opt/pakfire/pakfire upgrade -y'                    >> /tmp/pak_update
 echo '/opt/pakfire/pakfire upgrade -y'                    >> /tmp/pak_update
-echo '/usr/bin/logger -p syslog.emerg -t ipfire "Core-upgrade finished. If you use a customized grub.cfg"' >> /tmp/pak_update
+echo '/usr/bin/logger -p syslog.emerg -t ipfire "Core-upgrade finished. If you use a customized grub/uboot config"' >> /tmp/pak_update
 echo '/usr/bin/logger -p syslog.emerg -t ipfire "Check it before reboot !!!"' >> /tmp/pak_update
 echo '/usr/bin/logger -p syslog.emerg -t ipfire " *** Please reboot... *** "' >> /tmp/pak_update
 echo 'touch /var/run/need_reboot ' >> /tmp/pak_update
index c78a3c4ff697b4cf91e82f1bab1a42d64f117443..ec9022ddfad8305013f9efd1200818726c33bbf2 100644 (file)
@@ -272,7 +272,7 @@ my @temp;
 foreach (@channellist_cmd){
 $_ =~ /(.*) \[(\d+)(.*)\]/;
 $channel = $2;chomp $channel;
-if ( $channel =~ /\d+/ ){push(@temp,$channel);}
+if ( $channel =~ /\d+/ ){push(@temp,$channel + 0);}
 }
 @channellist = @temp;
 } else {
@@ -283,7 +283,7 @@ my @temp;
 foreach (@channellist_cmd){
 $_ =~ /(.*)Channel (\d+)(.*):/;
 $channel = $2;chomp $channel;
-if ( $channel =~ /\d+/ ){push(@temp,$channel);}
+if ( $channel =~ /\d+/ ){push(@temp,$channel + 0);}
 }
 @channellist = @temp;
 }
index cd48700d2b46f9c38ea3a67453f698dbbcb3c0f2..0eebe818db76d2fdfb745ae1136043bc7a2e3971 100644 (file)
@@ -92,6 +92,14 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.37-rt2800usb_add_dlink_dwa137_usbid.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/backports-3.18.1-1_add_libertas_uap.patch
 
+       # smsc mac address patch for pandaboard and raspberry pi
+ifeq "$(KCFG)" "-multi"
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10-smsc95xx-add_mac_addr_param.patch
+endif
+ifeq "$(KCFG)" "-rpi"
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10-smsc95xx-add_mac_addr_param.patch
+endif
+
        # generate config
        cd $(DIR_APP) && make KLIB=/lib/modules/$(KVER)-$(VERSUFIX)/ allmodconfig
 
index df3e39224f749f264de68ed2cdcacc659d2bc840..11d374e3b886a13fabdfbfca70309112c22ef3e7 100644 (file)
--- a/lfs/glibc
+++ b/lfs/glibc
@@ -268,12 +268,21 @@ endif
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966775.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh966778.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh970090.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh995972.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1008310.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1019916.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1022022.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1091162.patch
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1098050.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027101.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1027261.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1032628.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1044628.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1111460.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-1.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1133809-2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1139571.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1154563.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1170121.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc/glibc-rh1183533.patch
 
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-resolv-stack_chk_fail.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/glibc-remove-ctors-dtors-output-sections.patch
index c381a0a81fcb70fcfc80c7fada5cdd14421f2202..d066db25671908cb50e4092151c00f9231fba793 100644 (file)
@@ -32,7 +32,7 @@ DL_FROM    = $(URL_IPFIRE)
 DIR_APP    = $(DIR_SRC)/$(THISAPP)
 TARGET     = $(DIR_INFO)/$(THISAPP)
 PROG       = hostapd
-PAK_VER    = 31
+PAK_VER    = 32
 
 DEPS       = ""
 
index 4894710ac371923dc6c0921723e69593fbb9f726..f656c72a7458025459f1481a568a1721f4059804 100644 (file)
@@ -1,7 +1,7 @@
 ###############################################################################
 #                                                                             #
 # IPFire.org - A linux based firewall                                         #
-# Copyright (C) 2010  IPFire Team  <info@ipfire.org>                          #
+# Copyright (C) 2007-2015  IPFire Team  <info@ipfire.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        #
@@ -194,10 +194,12 @@ $(TARGET) :
                ln -sf any /etc/rc.d/init.d/networking/$$i; \
        done
 
-       # ARM does not need checkfstab and acpid
+       # ARM does not need checkfstab and acpid, intel no swconfig
 ifeq "$(MACHINE_TYPE)" "arm"
        rm -vf /etc/rc.d/init.d/{acpid,checkfstab}
+       ln -sf ../init.d/swconfig    /etc/rc.d/rcsysinit.d/S73swconfig
 else
+       rm -vf /etc/rc.d/init.d/swconfig
        ln -sf ../init.d/acpid       /etc/rc.d/rc3.d/S12acpid
        ln -sf ../init.d/acpid       /etc/rc.d/rc0.d/K87acpid
        ln -sf ../init.d/acpid       /etc/rc.d/rc6.d/K87acpid
index 5b0de460a656a46aa8a3628fd2d1462d03fef39d..2573d0a4d655b99be5e025f154f33ccc979d1d72 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
@@ -1,7 +1,7 @@
 ###############################################################################
 #                                                                             #
 # IPFire.org - A linux based firewall                                         #
-# Copyright (C) 2007-2014  IPFire Team <info@ipfire.org>                      #
+# Copyright (C) 2007-2015  IPFire Team <info@ipfire.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        #
 
 include Config
 
-VER        = 3.14.27
+VER        = 3.14.29
 
-RPI_PATCHES = 3.14.27-grsec-ipfire1
-A7M_PATCHES = 3.14.27-grsec-ipfire1
-GRS_PATCHES = grsecurity-3.0-3.14.27-201412170659.patch.xz
+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
 
 THISAPP    = linux-$(VER)
 DL_FILE    = linux-$(VER).tar.xz
@@ -37,7 +37,7 @@ DIR_APP    = $(DIR_SRC)/$(THISAPP)
 CFLAGS     =
 CXXFLAGS   =
 
-PAK_VER    = 55
+PAK_VER    = 56
 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                                 = 0af2d0702df6ee6d7181e697e0af3481
-rpi-patches-$(RPI_PATCHES).patch.xz_MD5                = 543a77d5602829f78b18788e5cb82188
-arm7-multi-patches-$(A7M_PATCHES).patch.xz_MD5 = 7014ce20d9ede588ea2c244d901cbeeb
-$(GRS_PATCHES)_MD5                             = 66af1d48af9dce2d0eb363bbc6bfb668
+$(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
 
 install : $(TARGET)
 
@@ -171,6 +171,12 @@ 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
 
 ifeq "$(KCFG)" "-rpi"
index dd1f0ac848b7a1bb09d279df8750d831849626c5..642d651823b694171fc16eafeb3add65263c6f6b 100644 (file)
@@ -78,6 +78,7 @@ $(subst %,%_MD5,$(objects)) :
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/strongswan-5.1.2-5.2.1_modp_custom.patch
        cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/strongswan-5.0.2_ipfire.patch
 
        cd $(DIR_APP) && [ -x "configure" ] || ./autogen.sh
diff --git a/lfs/swconfig b/lfs/swconfig
new file mode 100644 (file)
index 0000000..81e0b9f
--- /dev/null
@@ -0,0 +1,77 @@
+###############################################################################
+#                                                                             #
+# IPFire.org - A linux based firewall                                         #
+# Copyright (C) 2007-2015  IPFire Team  <info@ipfire.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 3 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.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER        = 001
+
+THISAPP    = swconfig-$(VER)
+DL_FILE    = $(THISAPP).tar.xz
+DL_FROM    = $(URL_IPFIRE)
+DIR_APP    = $(DIR_SRC)/$(THISAPP)
+TARGET     = $(DIR_INFO)/$(THISAPP)
+SUP_ARCH   = armv5tel
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE)
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+
+$(DL_FILE)_MD5 = c35919a05fc82b3f8b311da8dfc2cd3e
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+       @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+       @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+       @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+       @$(PREBUILD)
+       @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+       cd $(DIR_APP) && make $(MAKETUNING)
+       cd $(DIR_APP) && install -v -m755 swconfig /usr/bin/
+       @rm -rf $(DIR_APP)
+       @$(POSTBUILD)
diff --git a/make.sh b/make.sh
index 18ac3dac2a2e30f868cdccba2a98699d4eb7c094..531f8dbdd781888c9dfe24dc7a5b92ba21f6b509 100755 (executable)
--- a/make.sh
+++ b/make.sh
@@ -809,6 +809,7 @@ buildipfire() {
   ipfiremake squid-accounting
   ipfiremake pigz
   ipfiremake tmux
+  ipfiremake swconfig
 }
 
 buildinstaller() {
index 7de005eb41dd56e37be8e9491ce9474b9f9a7fc7..96bd12676cec3e0aed41344556a4249bdd720e91 100644 (file)
@@ -84,11 +84,14 @@ case "$1" in
                fi
 
                # Enable swap plugin if swap found
-               if [ "$(swapon -s | wc -l)" == "1" ]; then
+               if [ "$(swapon -s | wc -l)" == "0" ]; then
                        sed -i -e "s|^LoadPlugin swap|#LoadPlugin swap|g" /etc/collectd.conf
                else
                        sed -i -e "s|^#LoadPlugin swap|LoadPlugin swap|g" /etc/collectd.conf
                fi
+               
+               # sync after config update...
+               sync
 
                if [ $(date +%Y) -gt 2011 ]; then
                        boot_mesg "Starting Collection daemon..."
@@ -107,6 +110,8 @@ case "$1" in
                if [ "$(basename $0)" == "collectd" ]; then
                    /etc/init.d/tmpfs backup
                fi
+               # sync after backup...
+               sync
                ;;
        restart)
                ${0} stop
index 8f59a7f16fdb51c1fbe4c420eab4c89cba0d9a9b..357452cede860ef077fa4553413d3f500e83aab1 100644 (file)
@@ -106,8 +106,13 @@ case "${1}" in
                sleep 2
 
                if [ "$(/usr/sbin/iwconfig $INTERFACE | /bin/grep "Mode:Master")" == "" ]; then
-                       boot_mesg "Error! Can't set wlan master mode"
-                       echo_failure;
+                       killproc /usr/bin/hostapd > /dev/null 2>&1
+                       boot_mesg "Try to create additional AP device ..." 
+                       ip link set ${INTERFACE} down
+                       ip link set ${INTERFACE} name ${INTERFACE}_man
+                       iw dev  ${INTERFACE}_man interface add ${INTERFACE} type __ap
+                       evaluate_retval;
+                       /usr/bin/hostapd -P /var/run/hostapd /etc/hostapd.conf >/dev/null 2>&1 &
                        exit 0;
                else
                        echo_ok
@@ -116,7 +121,9 @@ case "${1}" in
 
        stop)
                boot_mesg "Stopping hostapd..."
-
+               ip link set ${INTERFACE} down > /dev/null 2>&1
+               ip link set ${INTERFACE} down_man > /dev/null 2>&1
+               sleep 1
                killproc /usr/bin/hostapd
                evaluate_retval
                ;;
index faa765055e95c21a8b5a81e0a4164e96f24a2c8f..9f7323f139b3578b04acddc0c100e925f786f1d6 100644 (file)
@@ -94,6 +94,11 @@ case "${1}" in
                setup_netdev_trigger nas6210:red:power ${RED_DEV} tx rx
                setup_netdev_trigger nas6210:red:usb_copy ${GREEN_DEV} tx rx
 
+               # Mirabox start
+               setup_heartbeat_trigger mirabox:green:pwr
+               setup_netdev_trigger mirabox:green:stat ${GREEN_DEV} tx rx
+               setup_netdev_trigger mirabox:blue:stat ${BLUE_DEV} tx rx
+
                exit 0
        ;;
 
@@ -132,6 +137,12 @@ case "${1}" in
                disable_led_trigger nas6210:red:power
                disable_led_trigger nas6210:red:usb_copy
 
+               # Mirabox stop
+               disable_led_trigger mirabox:green:pwr
+               enable_led mirabox:green:pwr
+               disable_led_trigger mirabox:green:stat
+               disable_led_trigger mirabox:blue:stat
+
                exit 0
        ;;
 
diff --git a/src/initscripts/init.d/swconfig b/src/initscripts/init.d/swconfig
new file mode 100644 (file)
index 0000000..be4604d
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/sh
+########################################################################
+# Begin $rc_base/init.d/swconfig
+#
+# Description : Script to setup lan switch.
+#               don't edit this script! If you want change the functions
+#               create an own script called swconfig.user
+########################################################################
+
+. /etc/sysconfig/rc
+. ${rc_functions}
+
+if [ -e /etc/init.d/swconfig.user ]; then
+       /etc/init.d/swconfig.user $*
+       exit ${?}
+fi
+
+if [ -e /var/ipfire/ethernet/swconfig_mac ]; then
+SWMAC=`cat /var/ipfire/ethernet/swconfig_mac`
+else
+# Generate a random local administrated mac address for vlan swconfig.
+SWMAC=`printf "%1x2:%02x:%02x:%02x:%02x" $[RANDOM%16] $[RANDOM%256] $[RANDOM%256] $[RANDOM%256] $[RANDOM%256]`
+echo $SWMAC > /var/ipfire/ethernet/swconfig_mac
+fi
+
+case "${1}" in
+       start)
+               case `cat /proc/device-tree/model` in
+                       "Lamobo-R1")
+                               #
+                               # Lamobo R1 aka BPi R1 Routerboard
+                               #
+                               # Speaker | LAN1 | LAN2 | LAN3 | LAN4 || LAN5 | HDMI
+                               # SW-Port |  P2  |  P1  |  P0  |  P4  ||  P3  |
+                               # VLAN    |  11  |  12  |  13  |  14  ||ALL(t)|
+                               #
+                               # Switch-Port P8 - ALL(t) boards internal CPU Port
+                               #
+                               device=`ls /sys/class/net/*/device/stmmac-0* | head -1 | cut -d/ -f5`
+                               ip link set $device up
+                               boot_mesg "Configure vlan-switch on $device ..."
+                               # Reset switch, counter and enable vlan mode
+                               swconfig dev $device set reset 1
+                               swconfig dev $device set reset_mib 1
+                               swconfig dev $device set enable_vlan 1
+                               # configure vlans
+                               swconfig dev $device vlan 11 set ports "2 3t 8t"
+                               swconfig dev $device vlan 12 set ports "1 3t 8t"
+                               swconfig dev $device vlan 13 set ports "0 3t 8t"
+                               swconfig dev $device vlan 14 set ports "4 3t 8t"
+                               # activate new config
+                               swconfig dev $device set apply 1
+                               # create interfaces for the vlan's
+                               modprobe 8021q
+                               vconfig add $device 11
+                               vconfig add $device 12
+                               vconfig add $device 13
+                               vconfig add $device 14
+                               # set local mac addresses.
+                               ip link set dev $device.11 address $SWMAC:11
+                               ip link set dev $device.12 address $SWMAC:12
+                               ip link set dev $device.13 address $SWMAC:13
+                               ip link set dev $device.14 address $SWMAC:14
+                               # need to restart udev...
+                               killall udevd
+                               /etc/init.d/udev start
+                       ;;
+               esac
+               exit 0
+       ;;
+
+       *)
+               echo "Usage: ${0} {start}"
+               exit 1
+       ;;
+esac
+
+# End $rc_base/init.d/swconfig
+
index c97776d24882b7b300d4fab497ffe9c9aa0655d2..358b2c46ffdf892a17a894ec7f6fbb6c2d367259 100644 (file)
@@ -245,7 +245,7 @@ static char* center_string(const char* str, int width) {
        return string;
 }
 
-#define DEFAULT_LANG "en_US.utf8"
+#define DEFAULT_LANG "en.utf8"
 #define NUM_LANGS 13
 
 static struct lang {
diff --git a/src/patches/glibc/glibc-rh1019916.patch b/src/patches/glibc/glibc-rh1019916.patch
new file mode 100644 (file)
index 0000000..f67af90
--- /dev/null
@@ -0,0 +1,39 @@
+commit 48b67d71ec677d1b3168e52a68b644784cead604
+Author: Andreas Schwab <schwab@redhat.com>
+Date:   Wed Sep 14 12:12:25 2011 +0200
+
+    Also relocate in dependency order when doing symbol dependency testing
+
+diff --git a/elf/rtld.c b/elf/rtld.c
+index 764140d..324d979 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -2027,24 +2027,21 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
+           {
+             /* We have to do symbol dependency testing.  */
+             struct relocate_args args;
+-            struct link_map *l;
++            unsigned int i;
+             args.reloc_mode = GLRO(dl_lazy) ? RTLD_LAZY : 0;
+-            l = main_map;
+-            while (l->l_next != NULL)
+-              l = l->l_next;
+-            do
++            i = main_map->l_searchlist.r_nlist;
++            while (i-- > 0)
+               {
++                struct link_map *l = main_map->l_initfini[i];
+                 if (l != &GL(dl_rtld_map) && ! l->l_faked)
+                   {
+                     args.l = l;
+                     _dl_receive_error (print_unresolved, relocate_doit,
+                                        &args);
+                   }
+-                l = l->l_prev;
+               }
+-            while (l != NULL);
+             if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+                 && rtld_multiple_ref)
diff --git a/src/patches/glibc/glibc-rh1027261.patch b/src/patches/glibc/glibc-rh1027261.patch
new file mode 100644 (file)
index 0000000..8599cf0
--- /dev/null
@@ -0,0 +1,28 @@
+commit 4d653a59ffeae0f46f76a40230e2cfa9587b7e7e
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Fri May 30 22:43:52 2014 +0530
+
+    Add mmap usage in malloc_info output
+    
+    The current malloc_info xml output only has information about
+    allocations on the heap.  Display information about number of mappings
+    and total mmapped size to this to complete the picture.
+
+diff -pruN a/malloc/malloc.c b/malloc/malloc.c
+--- a/malloc/malloc.c  2014-06-02 07:35:22.573256155 +0530
++++ b/malloc/malloc.c  2014-06-02 07:34:58.856257177 +0530
+@@ -6553,12 +6553,14 @@ malloc_info (int options, FILE *fp)
+   fprintf (fp,
+          "<total type=\"fast\" count=\"%zu\" size=\"%zu\"/>\n"
+          "<total type=\"rest\" count=\"%zu\" size=\"%zu\"/>\n"
++         "<total type=\"mmap\" count=\"%d\" size=\"%zu\"/>\n"
+          "<system type=\"current\" size=\"%zu\"/>\n"
+          "<system type=\"max\" size=\"%zu\"/>\n"
+          "<aspace type=\"total\" size=\"%zu\"/>\n"
+          "<aspace type=\"mprotect\" size=\"%zu\"/>\n"
+          "</malloc>\n",
+          total_nfastblocks, total_fastavail, total_nblocks, total_avail,
++         mp_.n_mmaps, mp_.mmapped_mem,
+          total_system, total_max_system,
+          total_aspace, total_aspace_mprotect);
diff --git a/src/patches/glibc/glibc-rh1032628.patch b/src/patches/glibc/glibc-rh1032628.patch
new file mode 100644 (file)
index 0000000..6140c19
--- /dev/null
@@ -0,0 +1,166 @@
+commit 028478fa40d85a73b19638dbe3f83b1acebf370c
+Author: Ulrich Drepper <drepper@gmail.com>
+Date:   Thu Mar 10 12:51:33 2011 -0500
+
+    Fix copy relocations handling of unique objects.
+
+ 2011-03-06  Ulrich Drepper  <drepper@gmail.com>
+
+and a part of:
+
+commit 33f85a3fb9fe432e0ebf6a3481bc2d5e29cb605f
+Author: Ulrich Drepper <drepper@gmail.com>
+Date:   Thu Mar 10 03:18:21 2011 -0500
+
+    Don't run tests checking xecutable stack when SELinux is enforcing.
+
+since the latter incorrectly had a bit of the former changes.
+
+Additionally, the test case needs -lstdc++ to build.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index c427679..56cb1b1 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -201,7 +201,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
+        unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
+        tst-audit1 tst-audit2 tst-audit9 \
+        tst-stackguard1 tst-addr1 tst-thrlock \
+-       tst-unique1 tst-unique2
++       tst-unique1 tst-unique2 tst-unique3
+ #      reldep9
+ test-srcs = tst-pathopt
+ tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
+@@ -255,6 +255,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+               order2mod1 order2mod2 order2mod3 order2mod4 \
+               tst-unique1mod1 tst-unique1mod2 \
+               tst-unique2mod1 tst-unique2mod2 \
++              tst-unique3lib tst-unique3lib2 \
+               tst-auditmod9a tst-auditmod9b
+ ifeq (yes,$(have-initfini-array))
+ modules-names += tst-array2dep tst-array5dep
+@@ -1178,6 +1179,11 @@ $(objpfx)tst-unique1.out: $(objpfx)tst-unique1mod1.so \
+ $(objpfx)tst-unique2: $(libdl) $(objpfx)tst-unique2mod1.so
+ $(objpfx)tst-unique2.out: $(objpfx)tst-unique2mod2.so
++LDLIBS-tst-unique3lib.so = -lstdc++
++LDLIBS-tst-unique3lib2.so = -lstdc++
++$(objpfx)tst-unique3: $(libdl) $(objpfx)tst-unique3lib.so
++$(objpfx)tst-unique3.out: $(objpfx)tst-unique3lib2.so
++
+ ifeq (yes,$(config-cflags-avx))
+ CFLAGS-tst-audit4.c += -mavx
+ CFLAGS-tst-auditmod4a.c += -mavx
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index 78c8669..874a4bb 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -364,8 +363,19 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+                     if (entries[idx].hashval == new_hash
+                         && strcmp (entries[idx].name, undef_name) == 0)
+                       {
+-                        result->s = entries[idx].sym;
+-                        result->m = (struct link_map *) entries[idx].map;
++                        if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
++                          {
++                            /* We possibly have to initialize the central
++                               copy from the copy addressed through the
++                               relocation.  */
++                            result->s = sym;
++                            result->m = (struct link_map *) map;
++                          }
++                        else
++                          {
++                            result->s = entries[idx].sym;
++                            result->m = (struct link_map *) entries[idx].map;
++                          }
+                         __rtld_lock_unlock_recursive (tab->lock);
+                         return 1;
+                       }
+diff --git a/elf/tst-unique3.cc b/elf/tst-unique3.cc
+new file mode 100644
+index 0000000..b2c9593
+--- /dev/null
++++ b/elf/tst-unique3.cc
+@@ -0,0 +1,23 @@
++#include "tst-unique3.h"
++#include <cstdio>
++#include "../dlfcn/dlfcn.h"
++
++int t = S<char>::i;
++
++int
++main (void)
++{
++  std::printf ("%d %d\n", S<char>::i, t);
++  int result = S<char>::i++ != 1 || t != 1;
++  result |= in_lib ();
++  void *d = dlopen ("$ORIGIN/tst-unique3lib2.so", RTLD_LAZY);
++  int (*fp) ();
++  if (d == NULL || (fp = (int(*)()) dlsym (d, "in_lib2")) == NULL)
++    {
++      std::printf ("failed to get symbol in_lib2\n");
++      return 1;
++    }
++  result |= fp ();
++  dlclose (d);
++  return result;
++}
+diff --git a/elf/tst-unique3.h b/elf/tst-unique3.h
+new file mode 100644
+index 0000000..716d236
+--- /dev/null
++++ b/elf/tst-unique3.h
+@@ -0,0 +1,8 @@
++// BZ 12510
++template<typename T>
++struct S
++{
++  static int i;
++};
++
++extern int in_lib (void);
+diff --git a/elf/tst-unique3lib.cc b/elf/tst-unique3lib.cc
+new file mode 100644
+index 0000000..fa8e85a
+--- /dev/null
++++ b/elf/tst-unique3lib.cc
+@@ -0,0 +1,11 @@
++#include <cstdio>
++#include "tst-unique3.h"
++template<typename T> int S<T>::i = 1;
++static int i = S<char>::i;
++
++int
++in_lib (void)
++{
++  std::printf ("in_lib: %d %d\n", S<char>::i, i);
++  return S<char>::i++ != 2 || i != 1;
++}
+diff --git a/elf/tst-unique3lib2.cc b/elf/tst-unique3lib2.cc
+new file mode 100644
+index 0000000..17d817e
+--- /dev/null
++++ b/elf/tst-unique3lib2.cc
+@@ -0,0 +1,12 @@
++#include <cstdio>
++#include "tst-unique3.h"
++
++template<typename T> int S<T>::i;
++
++extern "C"
++int
++in_lib2 ()
++{
++  std::printf ("in_lib2: %d\n", S<char>::i);
++  return S<char>::i != 3;
++}
+diff --git a/include/bits/dlfcn.h b/include/bits/dlfcn.h
+index cb4a5c2..c31a645 100644
+--- a/include/bits/dlfcn.h
++++ b/include/bits/dlfcn.h
+@@ -1,4 +1,3 @@
+ #include_next <bits/dlfcn.h>
+-extern void _dl_mcount_wrapper_check (void *__selfpc);
+ libc_hidden_proto (_dl_mcount_wrapper_check)
diff --git a/src/patches/glibc/glibc-rh1111460.patch b/src/patches/glibc/glibc-rh1111460.patch
new file mode 100644 (file)
index 0000000..1a4315d
--- /dev/null
@@ -0,0 +1,341 @@
+commit 7cbcdb3699584db8913ca90f705d6337633ee10f
+Author: Siddhesh Poyarekar <siddhesh@redhat.com>
+Date:   Fri Oct 25 10:22:12 2013 +0530
+
+    Fix stack overflow due to large AF_INET6 requests
+    
+    Resolves #16072 (CVE-2013-4458).
+    
+    This patch fixes another stack overflow in getaddrinfo when it is
+    called with AF_INET6.  The AF_UNSPEC case was fixed as CVE-2013-1914,
+    but the AF_INET6 case went undetected back then.
+
+commit 91ce40854d0b7f865cf5024ef95a8026b76096f3
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Fri Aug 16 09:38:52 2013 +0200
+
+    CVE-2013-4237, BZ #14699: Buffer overflow in readdir_r
+    
+       * sysdeps/posix/dirstream.h (struct __dirstream): Add errcode
+       member.
+       * sysdeps/posix/opendir.c (__alloc_dir): Initialize errcode
+       member.
+       * sysdeps/posix/rewinddir.c (rewinddir): Reset errcode member.
+       * sysdeps/posix/readdir_r.c (__READDIR_R): Enforce NAME_MAX limit.
+       Return delayed error code.  Remove GETDENTS_64BIT_ALIGNED
+       conditional.
+       * sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c: Do not define
+       GETDENTS_64BIT_ALIGNED.
+       * sysdeps/unix/sysv/linux/i386/readdir64_r.c: Likewise.
+       * manual/filesys.texi (Reading/Closing Directory): Document
+       ENAMETOOLONG return value of readdir_r.  Recommend readdir more
+       strongly.
+       * manual/conf.texi (Limits for Files): Add portability note to
+       NAME_MAX, PATH_MAX.
+       (Pathconf): Add portability note for _PC_NAME_MAX, _PC_PATH_MAX.
+
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index e6ce4cf..8ff74b4 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -197,7 +197,22 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
+                               &rc, &herrno, NULL, &localcanon));            \
+     if (rc != ERANGE || herrno != NETDB_INTERNAL)                           \
+       break;                                                                \
+-    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);                      \
++    if (!malloc_tmpbuf && __libc_use_alloca (alloca_used + 2 * tmpbuflen))    \
++      tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen, 2 * tmpbuflen,             \
++                                    alloca_used);                           \
++    else                                                                    \
++      {                                                                             \
++      char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL,                  \
++                            2 * tmpbuflen);                                 \
++      if (newp == NULL)                                                     \
++        {                                                                   \
++          result = -EAI_MEMORY;                                             \
++          goto free_and_return;                                             \
++        }                                                                   \
++      tmpbuf = newp;                                                        \
++      malloc_tmpbuf = true;                                                 \
++      tmpbuflen = 2 * tmpbuflen;                                            \
++      }                                                                             \
+   }                                                                         \
+   if (status == NSS_STATUS_SUCCESS && rc == 0)                                      \
+     h = &th;                                                                \
+@@ -209,7 +224,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
+       {                                                                     \
+         __set_h_errno (herrno);                                             \
+         _res.options = old_res_options;                                     \
+-        return -EAI_SYSTEM;                                                 \
++        result = -EAI_SYSTEM;                                               \
++        goto free_and_return;                                               \
+       }                                                                     \
+       if (herrno == TRY_AGAIN)                                                      \
+       no_data = EAI_AGAIN;                                                  \
+
+diff --git a/manual/conf.texi b/manual/conf.texi
+index 7eb8b36..c720063 100644
+--- a/manual/conf.texi
++++ b/manual/conf.texi
+@@ -1149,6 +1149,9 @@ typed ahead as input.  @xref{I/O Queues}.
+ @comment POSIX.1
+ @deftypevr Macro int NAME_MAX
+ The uniform system limit (if any) for the length of a file name component.
++
++@strong{Portability Note:} On some systems, the GNU C Library defines
++@code{NAME_MAX}, but does not actually enforce this limit.
+ @end deftypevr
+ @comment limits.h
+@@ -1157,6 +1160,9 @@ including the terminating null character.
+ @deftypevr Macro int PATH_MAX
+ The uniform system limit (if any) for the length of an entire file name (that
+ is, the argument given to system calls such as @code{open}).
++
++@strong{Portability Note:} The GNU C Library does not enforce this limit
++even if @code{PATH_MAX} is defined.
+ @end deftypevr
+ @cindex limits, pipe buffer size
+@@ -1476,6 +1482,9 @@ Inquire about the value of @code{POSIX_REC_MIN_XFER_SIZE}.
+ Inquire about the value of @code{POSIX_REC_XFER_ALIGN}.
+ @end table
++@strong{Portability Note:} On some systems, the GNU C Library does not
++enforce @code{_PC_NAME_MAX} or @code{_PC_PATH_MAX} limits.
++
+ @node Utility Limits
+ @section Utility Program Capacity Limits
+diff --git a/manual/filesys.texi b/manual/filesys.texi
+index 1df9cf2..814c210 100644
+--- a/manual/filesys.texi
++++ b/manual/filesys.texi
+@@ -444,9 +444,9 @@ symbols are declared in the header file @file{dirent.h}.
+ @comment POSIX.1
+ @deftypefun {struct dirent *} readdir (DIR *@var{dirstream})
+ This function reads the next entry from the directory.  It normally
+-returns a pointer to a structure containing information about the file.
+-This structure is statically allocated and can be rewritten by a
+-subsequent call.
++returns a pointer to a structure containing information about the
++file.  This structure is associated with the @var{dirstream} handle
++and can be rewritten by a subsequent call.
+ @strong{Portability Note:} On some systems @code{readdir} may not
+ return entries for @file{.} and @file{..}, even though these are always
+@@ -461,19 +461,61 @@ conditions are defined for this function:
+ The @var{dirstream} argument is not valid.
+ @end table
+-@code{readdir} is not thread safe.  Multiple threads using
+-@code{readdir} on the same @var{dirstream} may overwrite the return
+-value.  Use @code{readdir_r} when this is critical.
++To distinguish between an end-of-directory condition or an error, you
++must set @code{errno} to zero before calling @code{readdir}.  To avoid
++entering an infinite loop, you should stop reading from the directory
++after the first error.
++
++In POSIX.1-2008, @code{readdir} is not thread-safe.  In the GNU C Library
++implementation, it is safe to call @code{readdir} concurrently on
++different @var{dirstream}s, but multiple threads accessing the same
++@var{dirstream} result in undefined behavior.  @code{readdir_r} is a
++fully thread-safe alternative, but suffers from poor portability (see
++below).  It is recommended that you use @code{readdir}, with external
++locking if multiple threads access the same @var{dirstream}.
+ @end deftypefun
+ @comment dirent.h
+ @comment GNU
+ @deftypefun int readdir_r (DIR *@var{dirstream}, struct dirent *@var{entry}, struct dirent **@var{result})
+-This function is the reentrant version of @code{readdir}.  Like
+-@code{readdir} it returns the next entry from the directory.  But to
+-prevent conflicts between simultaneously running threads the result is
+-not stored in statically allocated memory.  Instead the argument
+-@var{entry} points to a place to store the result.
++This function is a version of @code{readdir} which performs internal
++locking.  Like @code{readdir} it returns the next entry from the
++directory.  To prevent conflicts between simultaneously running
++threads the result is stored inside the @var{entry} object.
++
++@strong{Portability Note:} It is recommended to use @code{readdir}
++instead of @code{readdir_r} for the following reasons:
++
++@itemize @bullet
++@item
++On systems which do not define @code{NAME_MAX}, it may not be possible
++to use @code{readdir_r} safely because the caller does not specify the
++length of the buffer for the directory entry.
++
++@item
++On some systems, @code{readdir_r} cannot read directory entries with
++very long names.  If such a name is encountered, the GNU C Library
++implementation of @code{readdir_r} returns with an error code of
++@code{ENAMETOOLONG} after the final directory entry has been read.  On
++other systems, @code{readdir_r} may return successfully, but the
++@code{d_name} member may not be NUL-terminated or may be truncated.
++
++@item
++POSIX-1.2008 does not guarantee that @code{readdir} is thread-safe,
++even when access to the same @var{dirstream} is serialized.  But in
++current implementations (including the GNU C Library), it is safe to call
++@code{readdir} concurrently on different @var{dirstream}s, so there is
++no need to use @code{readdir_r} in most multi-threaded programs.  In
++the rare case that multiple threads need to read from the same
++@var{dirstream}, it is still better to use @code{readdir} and external
++synchronization.
++
++@item
++It is expected that future versions of POSIX will obsolete
++@code{readdir_r} and mandate the level of thread safety for
++@code{readdir} which is provided by the GNU C Library and other
++implementations today.
++@end itemize
+ Normally @code{readdir_r} returns zero and sets @code{*@var{result}}
+ to @var{entry}.  If there are no more entries in the directory or an
+@@ -481,15 +523,6 @@ error is detected, @code{readdir_r} sets @code{*@var{result}} to a
+ null pointer and returns a nonzero error code, also stored in
+ @code{errno}, as described for @code{readdir}.
+-@strong{Portability Note:} On some systems @code{readdir_r} may not
+-return a NUL terminated string for the file name, even when there is no
+-@code{d_reclen} field in @code{struct dirent} and the file
+-name is the maximum allowed size.  Modern systems all have the
+-@code{d_reclen} field, and on old systems multi-threading is not
+-critical.  In any case there is no such problem with the @code{readdir}
+-function, so that even on systems without the @code{d_reclen} member one
+-could use multiple threads by using external locking.
+-
+ It is also important to look at the definition of the @code{struct
+ dirent} type.  Simply passing a pointer to an object of this type for
+ the second parameter of @code{readdir_r} might not be enough.  Some
+diff --git a/sysdeps/unix/dirstream.h b/sysdeps/unix/dirstream.h
+index a7a074d..8e8570d 100644
+--- a/sysdeps/unix/dirstream.h
++++ b/sysdeps/unix/dirstream.h
+@@ -39,6 +39,8 @@ struct __dirstream
+     off_t filepos;            /* Position of next entry to read.  */
++    int errcode;              /* Delayed error code.  */
++
+     /* Directory block.  */
+     char data[0] __attribute__ ((aligned (__alignof__ (void*))));
+   };
+diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c
+index ddfc3a7..fc05b0f 100644
+--- a/sysdeps/unix/opendir.c
++++ b/sysdeps/unix/opendir.c
+@@ -231,6 +231,7 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp)
+   dirp->size = 0;
+   dirp->offset = 0;
+   dirp->filepos = 0;
++  dirp->errcode = 0;
+   return dirp;
+ }
+diff --git a/sysdeps/unix/readdir_r.c b/sysdeps/unix/readdir_r.c
+index b5a8e2e..8ed5c3f 100644
+--- a/sysdeps/unix/readdir_r.c
++++ b/sysdeps/unix/readdir_r.c
+@@ -40,6 +40,7 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
+   DIRENT_TYPE *dp;
+   size_t reclen;
+   const int saved_errno = errno;
++  int ret;
+   __libc_lock_lock (dirp->lock);
+@@ -70,10 +71,10 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
+                 bytes = 0;
+                 __set_errno (saved_errno);
+               }
++            if (bytes < 0)
++              dirp->errcode = errno;
+             dp = NULL;
+-            /* Reclen != 0 signals that an error occurred.  */
+-            reclen = bytes != 0;
+             break;
+           }
+         dirp->size = (size_t) bytes;
+@@ -106,28 +107,46 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
+       dirp->filepos += reclen;
+ #endif
+-      /* Skip deleted files.  */
++#ifdef NAME_MAX
++      if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1)
++      {
++        /* The record is very long.  It could still fit into the
++           caller-supplied buffer if we can skip padding at the
++           end.  */
++        size_t namelen = _D_EXACT_NAMLEN (dp);
++        if (namelen <= NAME_MAX)
++          reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1;
++        else
++          {
++            /* The name is too long.  Ignore this file.  */
++            dirp->errcode = ENAMETOOLONG;
++            dp->d_ino = 0;
++            continue;
++          }
++      }
++#endif
++
++      /* Skip deleted and ignored files.  */
+     }
+   while (dp->d_ino == 0);
+   if (dp != NULL)
+     {
+-#ifdef GETDENTS_64BIT_ALIGNED
+-      /* The d_reclen value might include padding which is not part of
+-       the DIRENT_TYPE data structure.  */
+-      reclen = MIN (reclen, sizeof (DIRENT_TYPE));
+-#endif
+       *result = memcpy (entry, dp, reclen);
+-#ifdef GETDENTS_64BIT_ALIGNED
++#ifdef _DIRENT_HAVE_D_RECLEN
+       entry->d_reclen = reclen;
+ #endif
++      ret = 0;
+     }
+   else
+-    *result = NULL;
++    {
++      *result = NULL;
++      ret = dirp->errcode;
++    }
+   __libc_lock_unlock (dirp->lock);
+-  return dp != NULL ? 0 : reclen ? errno : 0;
++  return ret;
+ }
+ #ifdef __READDIR_R_ALIAS
+diff --git a/sysdeps/unix/rewinddir.c b/sysdeps/unix/rewinddir.c
+index 2935a8e..d4991ad 100644
+--- a/sysdeps/unix/rewinddir.c
++++ b/sysdeps/unix/rewinddir.c
+@@ -33,5 +33,6 @@ rewinddir (dirp)
+   dirp->filepos = 0;
+   dirp->offset = 0;
+   dirp->size = 0;
++  dirp->errcode = 0;
+   __libc_lock_unlock (dirp->lock);
+ }
+diff --git a/sysdeps/unix/sysv/linux/i386/readdir64_r.c b/sysdeps/unix/sysv/linux/i386/readdir64_r.c
+index 8ebbcfd..a7d114e 100644
+--- a/sysdeps/unix/sysv/linux/i386/readdir64_r.c
++++ b/sysdeps/unix/sysv/linux/i386/readdir64_r.c
+@@ -18,7 +18,6 @@
+ #define __READDIR_R __readdir64_r
+ #define __GETDENTS __getdents64
+ #define DIRENT_TYPE struct dirent64
+-#define GETDENTS_64BIT_ALIGNED 1
+ #include <sysdeps/unix/readdir_r.c>
diff --git a/src/patches/glibc/glibc-rh1139571.patch b/src/patches/glibc/glibc-rh1139571.patch
new file mode 100644 (file)
index 0000000..b1320a7
--- /dev/null
@@ -0,0 +1,154 @@
+commit 41488498b6d9440ee66ab033808cce8323bba7ac
+Author: Florian Weimer <fweimer@redhat.com>
+Date:   Wed Sep 3 19:45:43 2014 +0200
+
+    CVE-2014-6040: Crashes on invalid input in IBM gconv modules [BZ #17325]
+    
+    These changes are based on the fix for BZ #14134 in commit
+    6e230d11837f3ae7b375ea69d7905f0d18eb79e5.
+
+diff --git a/iconvdata/Makefile b/iconvdata/Makefile
+index 0a410a1..b6327d6 100644
+--- a/iconvdata/Makefile
++++ b/iconvdata/Makefile
+@@ -297,6 +297,7 @@ $(objpfx)tst-iconv7.out: $(objpfx)gconv-modules \
+ $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
+                        $(addprefix $(objpfx),$(modules.so)) \
+                        $(common-objdir)/iconv/iconv_prog TESTS
++      iconv_modules="$(modules)" \
+       $(SHELL) -e $< $(common-objdir) > $@
+ $(objpfx)tst-tables.out: tst-tables.sh $(objpfx)gconv-modules \
+diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c
+index 0b5484f..cf80993 100644
+--- a/iconvdata/ibm1364.c
++++ b/iconvdata/ibm1364.c
+@@ -221,7 +221,8 @@ enum
+         ++rp2;                                                              \
+                                                                             \
+       uint32_t res;                                                         \
+-      if (__builtin_expect (ch < rp2->start, 0)                             \
++      if (__builtin_expect (rp2->start == 0xffff, 0)                        \
++          || __builtin_expect (ch < rp2->start, 0)                          \
+           || (res = DB_TO_UCS4[ch + rp2->idx],                              \
+               __builtin_expect (res, L'\1') == L'\0' && ch != '\0'))        \
+         {                                                                   \
+diff --git a/iconvdata/ibm932.c b/iconvdata/ibm932.c
+index f5dca59..aa69d65 100644
+--- a/iconvdata/ibm932.c
++++ b/iconvdata/ibm932.c
+@@ -74,11 +74,12 @@
+         }                                                                   \
+                                                                             \
+       ch = (ch * 0x100) + inptr[1];                                         \
++      /* ch was less than 0xfd.  */                                         \
++      assert (ch < 0xfd00);                                                 \
+       while (ch > rp2->end)                                                 \
+         ++rp2;                                                              \
+                                                                             \
+-      if (__builtin_expect (rp2 == NULL, 0)                                 \
+-          || __builtin_expect (ch < rp2->start, 0)                          \
++      if (__builtin_expect (ch < rp2->start, 0)                             \
+           || (res = __ibm932db_to_ucs4[ch + rp2->idx],                      \
+           __builtin_expect (res, '\1') == 0 && ch !=0))                     \
+         {                                                                   \
+diff --git a/iconvdata/ibm933.c b/iconvdata/ibm933.c
+index f46dfb5..461fb5e 100644
+--- a/iconvdata/ibm933.c
++++ b/iconvdata/ibm933.c
+@@ -162,7 +162,7 @@ enum
+       while (ch > rp2->end)                                                 \
+         ++rp2;                                                              \
+                                                                             \
+-      if (__builtin_expect (rp2 == NULL, 0)                                 \
++      if (__builtin_expect (rp2->start == 0xffff, 0)                        \
+           || __builtin_expect (ch < rp2->start, 0)                          \
+           || (res = __ibm933db_to_ucs4[ch + rp2->idx],                      \
+               __builtin_expect (res, L'\1') == L'\0' && ch != '\0'))        \
+diff --git a/iconvdata/ibm935.c b/iconvdata/ibm935.c
+index a8e4e6c..132d816 100644
+--- a/iconvdata/ibm935.c
++++ b/iconvdata/ibm935.c
+@@ -162,7 +162,7 @@ enum
+       while (ch > rp2->end)                                                 \
+         ++rp2;                                                              \
+                                                                             \
+-      if (__builtin_expect (rp2 == NULL, 0)                                 \
++      if (__builtin_expect (rp2->start == 0xffff, 0)                        \
+           || __builtin_expect (ch < rp2->start, 0)                          \
+           || (res = __ibm935db_to_ucs4[ch + rp2->idx],                      \
+               __builtin_expect (res, L'\1') == L'\0' && ch != '\0'))        \
+diff --git a/iconvdata/ibm937.c b/iconvdata/ibm937.c
+index 239be61..69b154d 100644
+--- a/iconvdata/ibm937.c
++++ b/iconvdata/ibm937.c
+@@ -162,7 +162,7 @@ enum
+       while (ch > rp2->end)                                                 \
+         ++rp2;                                                              \
+                                                                             \
+-      if (__builtin_expect (rp2 == NULL, 0)                                 \
++      if (__builtin_expect (rp2->start == 0xffff, 0)                        \
+           || __builtin_expect (ch < rp2->start, 0)                          \
+           || (res = __ibm937db_to_ucs4[ch + rp2->idx],                      \
+               __builtin_expect (res, L'\1') == L'\0' && ch != '\0'))        \
+diff --git a/iconvdata/ibm939.c b/iconvdata/ibm939.c
+index 5d0db36..9936e2c 100644
+--- a/iconvdata/ibm939.c
++++ b/iconvdata/ibm939.c
+@@ -162,7 +162,7 @@ enum
+       while (ch > rp2->end)                                                 \
+         ++rp2;                                                              \
+                                                                             \
+-      if (__builtin_expect (rp2 == NULL, 0)                                 \
++      if (__builtin_expect (rp2->start == 0xffff, 0)                        \
+           || __builtin_expect (ch < rp2->start, 0)                          \
+           || (res = __ibm939db_to_ucs4[ch + rp2->idx],                      \
+               __builtin_expect (res, L'\1') == L'\0' && ch != '\0'))        \
+diff --git a/iconvdata/ibm943.c b/iconvdata/ibm943.c
+index be0c14f..c5d5742 100644
+--- a/iconvdata/ibm943.c
++++ b/iconvdata/ibm943.c
+@@ -75,11 +75,12 @@
+         }                                                                   \
+                                                                             \
+       ch = (ch * 0x100) + inptr[1];                                         \
++      /* ch was less than 0xfd.  */                                         \
++      assert (ch < 0xfd00);                                                 \
+       while (ch > rp2->end)                                                 \
+         ++rp2;                                                              \
+                                                                             \
+-      if (__builtin_expect (rp2 == NULL, 0)                                 \
+-          || __builtin_expect (ch < rp2->start, 0)                          \
++      if (__builtin_expect (ch < rp2->start, 0)                             \
+           || (res = __ibm943db_to_ucs4[ch + rp2->idx],                      \
+           __builtin_expect (res, '\1') == 0 && ch !=0))                     \
+         {                                                                   \
+diff --git a/iconvdata/run-iconv-test.sh b/iconvdata/run-iconv-test.sh
+index c98c929..5dfb69f 100755
+--- a/iconvdata/run-iconv-test.sh
++++ b/iconvdata/run-iconv-test.sh
+@@ -184,6 +184,24 @@ while read utf8 from filename; do
+ done < TESTS2
++# Check for crashes in decoders.
++printf '\016\377\377\377\377\377\377\377' > $temp1
++for from in $iconv_modules ; do
++    echo $ac_n "test decoder $from $ac_c"
++    PROG=`eval echo $ICONV`
++    if $PROG < $temp1 >/dev/null 2>&1 ; then
++      : # fall through
++    else
++      status=$?
++      if test $status -gt 1 ; then
++          echo "/FAILED"
++          failed=1
++          continue
++      fi
++    fi
++    echo "OK"
++done
++
+ exit $failed
+ # Local Variables:
+ #  mode:shell-script
diff --git a/src/patches/glibc/glibc-rh1154563.patch b/src/patches/glibc/glibc-rh1154563.patch
new file mode 100644 (file)
index 0000000..22821b1
--- /dev/null
@@ -0,0 +1,333 @@
+#
+# This is a special patch for rhel-6 to fix recursive dlopen.
+# It is likely the upstream patch will always be too risky for
+# rhel-6 and will involve reorganizing the way in which recursive
+# dlopen is allowed to operate and how the _r_debug and stap
+# points are used by gdb for the recursive case.
+#
+# This fix changes the internal API to duplicate the ldconfig
+# cache data. This means that at any point the cache can be
+# unmapped without any consequences. The caller is responsible
+# fore freeing the returned string.
+#
+# A regression test is added to verify the assertion for _r_debug
+# is no longer triggered due to the recursive dlopen. The test to
+# verify the fix in _dl_load_cache_lookup is not automated and
+# has to be run by hand.
+#
+diff -urN glibc-2.12-2-gc4ccff1/elf/dl-cache.c glibc-2.12-2-gc4ccff1.mod/elf/dl-cache.c
+--- glibc-2.12-2-gc4ccff1/elf/dl-cache.c       2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-cache.c   2014-12-10 21:54:08.801985045 -0500
+@@ -175,9 +175,12 @@
+ /* Look up NAME in ld.so.cache and return the file name stored there,
+-   or null if none is found.  */
+-
+-const char *
++   or null if none is found. 
++   The caller is responsible for freeing the returned string.  The ld.so.cache
++   may be unmapped at any time by a completing recursive dlopen and
++   this function must take care that it does not return references to
++   any data in the mapping.  */
++char *
+ internal_function
+ _dl_load_cache_lookup (const char *name)
+ {
+@@ -290,7 +293,17 @@
+       && best != NULL)
+     _dl_debug_printf ("  trying file=%s\n", best);
+-  return best;
++  if (best == NULL)
++    return NULL;
++
++  /* The double copy is *required* since malloc may be interposed
++     and call dlopen itself whose completion would unmap the data
++     we are accessing. Therefore we must make the copy of the
++     mapping data without using malloc.  */
++  char *temp;
++  temp = alloca (strlen (best) + 1);
++  strcpy (temp, best);
++  return strdup (temp);
+ }
+ #ifndef MAP_COPY
+diff -urN glibc-2.12-2-gc4ccff1/elf/dl-load.c glibc-2.12-2-gc4ccff1.mod/elf/dl-load.c
+--- glibc-2.12-2-gc4ccff1/elf/dl-load.c        2014-12-10 11:03:17.966048404 -0500
++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-load.c    2014-12-10 21:47:29.319387538 -0500
+@@ -2126,7 +2126,7 @@
+       {
+         /* Check the list of libraries in the file /etc/ld.so.cache,
+            for compatibility with Linux's ldconfig program.  */
+-        const char *cached = _dl_load_cache_lookup (name);
++        char *cached = _dl_load_cache_lookup (name);
+         if (cached != NULL)
+           {
+@@ -2156,6 +2156,7 @@
+                     if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0)
+                       {
+                         /* The prefix matches.  Don't use the entry.  */
++                        free (cached);
+                         cached = NULL;
+                         break;
+                       }
+@@ -2172,14 +2173,9 @@
+                                   &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
+                                   LA_SER_CONFIG, &found_other_class, false);
+                 if (__builtin_expect (fd != -1, 1))
+-                  {
+-                    realname = local_strdup (cached);
+-                    if (realname == NULL)
+-                      {
+-                        __close (fd);
+-                        fd = -1;
+-                      }
+-                  }
++                  realname = cached;
++                else
++                  free (cached);
+               }
+           }
+       }
+diff -urN glibc-2.12-2-gc4ccff1/elf/dl-open.c glibc-2.12-2-gc4ccff1.mod/elf/dl-open.c
+--- glibc-2.12-2-gc4ccff1/elf/dl-open.c        2014-12-10 11:03:18.083048497 -0500
++++ glibc-2.12-2-gc4ccff1.mod/elf/dl-open.c    2014-12-10 20:34:16.017503638 -0500
+@@ -220,7 +220,11 @@
+       }
+     }
+-  assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
++  /* One might be tempted to assert that we are RT_CONSISTENT at this point, but that
++     may not be true if this is a recursive call to dlopen.
++     TODO: Fix all of the debug state so we end up at RT_CONSISTENT only when the last
++     recursive dlopen completes.  */
++  _dl_debug_initialize (0, args->nsid);
+   /* Load the named object.  */
+   struct link_map *new;
+diff -urN glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h glibc-2.12-2-gc4ccff1.mod/sysdeps/generic/ldsodefs.h
+--- glibc-2.12-2-gc4ccff1/sysdeps/generic/ldsodefs.h   2014-12-10 11:03:17.944048387 -0500
++++ glibc-2.12-2-gc4ccff1.mod/sysdeps/generic/ldsodefs.h       2014-12-10 21:46:14.071344018 -0500
+@@ -996,8 +996,8 @@
+      internal_function;
+ /* Look up NAME in ld.so.cache and return the file name stored there,
+-   or null if none is found.  */
+-extern const char *_dl_load_cache_lookup (const char *name)
++   or null if none is found.  Caller must free returned string.  */
++extern char *_dl_load_cache_lookup (const char *name)
+      internal_function;
+ /* If the system does not support MAP_COPY we cannot leave the file open
+diff -urN glibc-2.12-2-gc4ccff1/dlfcn/Makefile glibc-2.12-2-gc4ccff1.mod/dlfcn/Makefile
+--- glibc-2.12-2-gc4ccff1/dlfcn/Makefile       2010-05-04 07:27:23.000000000 -0400
++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/Makefile   2014-12-11 16:58:55.719803063 -0500
+@@ -42,12 +42,12 @@
+ ifeq (yes,$(build-shared))
+ tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
+       bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
+-      bug-atexit3 tstatexit
++      bug-atexit3 tstatexit tst-rec-dlopen
+ endif
+ modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
+               defaultmod2 errmsg1mod modatexit modcxaatexit \
+               bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \
+-              bug-atexit2-lib bug-atexit3-lib
++              bug-atexit2-lib bug-atexit3-lib moddummy1 moddummy2
+ failtestmod.so-no-z-defs = yes
+ glreflib2.so-no-z-defs = yes
+@@ -142,6 +142,8 @@
+ $(objpfx)bug-atexit3-lib.so: $(common-objpfx)libc.so \
+                            $(common-objpfx)libc_nonshared.a
++LDLIBS-tst-rec-dlopen = -ldl
++$(objpfx)tst-rec-dlopen: $(libdl)
+ # Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+ # This ensures they will load libc.so for needed symbols if loaded by
+diff -urN glibc-2.12-2-gc4ccff1/dlfcn/moddummy1.c glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy1.c
+--- glibc-2.12-2-gc4ccff1/dlfcn/moddummy1.c    1969-12-31 19:00:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy1.c        2014-12-11 16:57:54.108797285 -0500
+@@ -0,0 +1,13 @@
++/* Provide a dummy DSO for tst-recursive-dlopen to use.  */
++#include <stdio.h>
++#include <stdlib.h>
++
++int called_dummy1;
++
++void
++dummy1 (void)
++{
++  printf ("Called dummy1()\n");
++  called_dummy1++;
++}
++
+diff -urN glibc-2.12-2-gc4ccff1/dlfcn/moddummy2.c glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy2.c
+--- glibc-2.12-2-gc4ccff1/dlfcn/moddummy2.c    1969-12-31 19:00:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/moddummy2.c        2014-12-11 16:57:54.108797285 -0500
+@@ -0,0 +1,13 @@
++/* Provide a dummy DSO for tst-recursive-dlopen to use.  */
++#include <stdio.h>
++#include <stdlib.h>
++
++int called_dummy2;
++
++void
++dummy2 (void)
++{
++  printf ("Called dummy2()\n");
++  called_dummy2++;
++}
++
+diff -urN glibc-2.12-2-gc4ccff1/dlfcn/tst-rec-dlopen.c glibc-2.12-2-gc4ccff1.mod/dlfcn/tst-rec-dlopen.c
+--- glibc-2.12-2-gc4ccff1/dlfcn/tst-rec-dlopen.c       1969-12-31 19:00:00.000000000 -0500
++++ glibc-2.12-2-gc4ccff1.mod/dlfcn/tst-rec-dlopen.c   2014-12-11 20:53:28.617848774 -0500
+@@ -0,0 +1,145 @@
++/* Test recursive dlopen using malloc hooks.
++   Copyright (C) 1998-2014 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library 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
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <malloc.h>
++#include <dlfcn.h>
++
++#define DSO "moddummy1.so"
++#define FUNC "dummy1"
++
++#define DSO1 "moddummy2.so"
++#define FUNC1 "dummy2"
++
++/* Prevent the compiler from moving the assignment to called_func
++   before (*func)() since the compiler doesn't know we might abort
++   or catch a SIGSEGV signal and it may move the store.  */
++volatile int called_func;
++
++/* Prototype for my hook.  */
++void *custom_malloc_hook (size_t, const void *);
++
++/* Pointer to old malloc hooks.  */
++void *(*old_malloc_hook) (size_t, const void *);
++
++/* Call function func_name in DSO dso_name via dlopen.  */
++void
++call_func (const char *dso_name, const char *func_name)
++{
++  int ret;
++  void *dso;
++  void (*func) (void);
++  char *err;
++
++  /* Open the DSO.  */
++  dso = dlopen (dso_name, RTLD_NOW|RTLD_GLOBAL);
++  if (dso == NULL)
++    {
++      err = dlerror ();
++      fprintf (stderr, "%s\n", err);
++      exit (1);
++    }
++  /* Clear any errors.  */
++  dlerror ();
++
++  /* Lookup func.  */
++  *(void **) (&func) = dlsym (dso, func_name);
++  if (func == NULL)
++    {
++      err = dlerror ();
++      if (err != NULL)
++        {
++        fprintf (stderr, "%s\n", err);
++        exit (1);
++        }
++    }
++  /* Call func.  */
++  (*func) ();
++  called_func = 1;
++
++  /* Close the library and look for errors too.  */
++  ret = dlclose (dso);
++  if (ret != 0)
++    {
++      err = dlerror ();
++      fprintf (stderr, "%s\n", err);
++      exit (1);
++    }
++
++}
++
++/* Empty hook that does nothing.  */
++void *
++custom_malloc_hook (size_t size, const void *caller)
++{
++  void *result;
++  /* Restore old hooks.  */
++  __malloc_hook = old_malloc_hook;
++  /* First call a function in another library via dlopen.  */
++  call_func (DSO1, FUNC1);
++  /* Called recursively.  */
++  result = malloc (size);
++  /* Restore new hooks.  */
++  __malloc_hook = custom_malloc_hook;
++  return result;
++}
++
++static int
++do_test (void)
++{
++  /* Save old hook.  */
++  old_malloc_hook = __malloc_hook;
++  /* Install new hook.  */
++  __malloc_hook = custom_malloc_hook;
++
++  /* Bug 17702 fixes two things:
++       * A recursive dlopen unmapping the ld.so.cache.
++       * An assertion that _r_debug is RT_CONSISTENT at entry to dlopen.
++     We can only test the latter. Testing the former requires modifying
++     ld.so.conf to cache the dummy libraries, then running ldconfig,
++     then run the test. If you do all of that (and glibc's test
++     infrastructure doesn't support that yet) then the test will
++     SEGFAULT without the fix. If you don't do that, then the test
++     will abort because of the assert described in detail below.  */
++  call_func (DSO, FUNC);
++
++  /* Restore old hook.  */
++  __malloc_hook = old_malloc_hook;
++
++  /* The function dummy2() is called by the malloc hook. Check to
++     see that it was called. This ensures the second recursive
++     dlopen happened and we called the function in that library.
++
++     Before the fix you either get a SIGSEGV when accessing mmap'd
++     ld.so.cache data or an assertion failure about _r_debug not
++     beint RT_CONSISTENT.  We don't test for the SIGSEGV since it
++     would require finding moddummy1 or moddummy2 in the cache and
++     we don't have any infrastructure to test that, but the _r_debug
++     assertion triggers.  */
++  if (called_func > 0)
++    printf ("PASS: Function call_func() called more than once.\n");
++  else
++    printf ("FAIL: Function call_func() not called.\n");
++
++  return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
diff --git a/src/patches/glibc/glibc-rh1170121.patch b/src/patches/glibc/glibc-rh1170121.patch
new file mode 100644 (file)
index 0000000..1accbf3
--- /dev/null
@@ -0,0 +1,163 @@
+#
+# commit a39208bd7fb76c1b01c127b4c61f9bfd915bfe7c
+# Author: Carlos O'Donell <carlos@redhat.com>
+# Date:   Wed Nov 19 11:44:12 2014 -0500
+# 
+#     CVE-2014-7817: wordexp fails to honour WRDE_NOCMD.
+#     
+#     The function wordexp() fails to properly handle the WRDE_NOCMD
+#     flag when processing arithmetic inputs in the form of "$((... ``))"
+#     where "..." can be anything valid. The backticks in the arithmetic
+#     epxression are evaluated by in a shell even if WRDE_NOCMD forbade
+#     command substitution. This allows an attacker to attempt to pass
+#     dangerous commands via constructs of the above form, and bypass
+#     the WRDE_NOCMD flag. This patch fixes this by checking for WRDE_NOCMD
+#     in exec_comm(), the only place that can execute a shell. All other
+#     checks for WRDE_NOCMD are superfluous and removed.
+#     
+#     We expand the testsuite and add 3 new regression tests of roughly
+#     the same form but with a couple of nested levels.
+#     
+#     On top of the 3 new tests we add fork validation to the WRDE_NOCMD
+#     testing. If any forks are detected during the execution of a wordexp()
+#     call with WRDE_NOCMD, the test is marked as failed. This is slightly
+#     heuristic since vfork might be used in the future, but it provides a
+#     higher level of assurance that no shells were executed as part of
+#     command substitution with WRDE_NOCMD in effect. In addition it doesn't
+#     require libpthread or libdl, instead we use the public implementation
+#     namespace function __register_atfork (already part of the public ABI
+#     for libpthread).
+#     
+#     Tested on x86_64 with no regressions.
+# 
+diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
+index 4957006..bdd65e4 100644
+--- a/posix/wordexp-test.c
++++ b/posix/wordexp-test.c
+@@ -27,6 +27,25 @@
+ #define IFS " \n\t"
++extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden")));
++extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
++
++static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void))
++{
++  return __register_atfork (prepare, parent, child,
++                          &__dso_handle == NULL ? NULL : __dso_handle);
++}
++
++/* Number of forks seen.  */
++static int registered_forks;
++
++/* For each fork increment the fork count.  */
++static void
++register_fork (void)
++{
++  registered_forks++;
++}
++
+ struct test_case_struct
+ {
+   int retval;
+@@ -206,6 +225,12 @@ struct test_case_struct
+     { WRDE_SYNTAX, NULL, "$((2+))", 0, 0, { NULL, }, IFS },
+     { WRDE_SYNTAX, NULL, "`", 0, 0, { NULL, }, IFS },
+     { WRDE_SYNTAX, NULL, "$((010+4+))", 0, 0, { NULL }, IFS },
++    /* Test for CVE-2014-7817. We test 3 combinations of command
++       substitution inside an arithmetic expression to make sure that
++       no commands are executed and error is returned.  */
++    { WRDE_CMDSUB, NULL, "$((`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
++    { WRDE_CMDSUB, NULL, "$((1+`echo 1`))", WRDE_NOCMD, 0, { NULL, }, IFS },
++    { WRDE_CMDSUB, NULL, "$((1+$((`echo 1`))))", WRDE_NOCMD, 0, { NULL, }, IFS },
+     { -1, NULL, NULL, 0, 0, { NULL, }, IFS },
+   };
+@@ -258,6 +283,15 @@ main (int argc, char *argv[])
+         return -1;
+     }
++  /* If we are not allowed to do command substitution, we install
++     fork handlers to verify that no forks happened.  No forks should
++     happen at all if command substitution is disabled.  */
++  if (__app_register_atfork (register_fork, NULL, NULL) != 0)
++    {
++      printf ("Failed to register fork handler.\n");
++      return -1;
++    }
++
+   for (test = 0; test_case[test].retval != -1; test++)
+     if (testit (&test_case[test]))
+       ++fail;
+@@ -367,6 +401,9 @@ testit (struct test_case_struct *tc)
+   printf ("Test %d (%s): ", ++tests, tc->words);
++  if (tc->flags & WRDE_NOCMD)
++    registered_forks = 0;
++
+   if (tc->flags & WRDE_APPEND)
+     {
+       /* initial wordexp() call, to be appended to */
+@@ -378,6 +415,13 @@ testit (struct test_case_struct *tc)
+     }
+   retval = wordexp (tc->words, &we, tc->flags);
++  if ((tc->flags & WRDE_NOCMD)
++      && (registered_forks > 0))
++    {
++        printf ("FAILED fork called for WRDE_NOCMD\n");
++        return 1;
++    }
++
+   if (tc->flags & WRDE_DOOFFS)
+       start_offs = sav_we.we_offs;
+diff --git a/posix/wordexp.c b/posix/wordexp.c
+index b6b65dd..26f3a26 100644
+--- a/posix/wordexp.c
++++ b/posix/wordexp.c
+@@ -893,6 +893,10 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length,
+   pid_t pid;
+   int noexec = 0;
++  /* Do nothing if command substitution should not succeed.  */
++  if (flags & WRDE_NOCMD)
++    return WRDE_CMDSUB;
++
+   /* Don't fork() unless necessary */
+   if (!comm || !*comm)
+     return 0;
+@@ -2082,9 +2086,6 @@ parse_dollars (char **word, size_t *word_length, size_t *max_length,
+           }
+       }
+-      if (flags & WRDE_NOCMD)
+-      return WRDE_CMDSUB;
+-
+       (*offset) += 2;
+       return parse_comm (word, word_length, max_length, words, offset, flags,
+                        quoted? NULL : pwordexp, ifs, ifs_white);
+@@ -2196,9 +2197,6 @@ parse_dquote (char **word, size_t *word_length, size_t *max_length,
+         break;
+       case '`':
+-        if (flags & WRDE_NOCMD)
+-          return WRDE_CMDSUB;
+-
+         ++(*offset);
+         error = parse_backtick (word, word_length, max_length, words,
+                                 offset, flags, NULL, NULL, NULL);
+@@ -2357,12 +2355,6 @@ wordexp (const char *words, wordexp_t *pwordexp, int flags)
+       break;
+       case '`':
+-      if (flags & WRDE_NOCMD)
+-        {
+-          error = WRDE_CMDSUB;
+-          goto do_error;
+-        }
+-
+       ++words_offset;
+       error = parse_backtick (&word, &word_length, &max_length, words,
+                               &words_offset, flags, pwordexp, ifs,
diff --git a/src/patches/glibc/glibc-rh1183533.patch b/src/patches/glibc/glibc-rh1183533.patch
new file mode 100644 (file)
index 0000000..9263cd5
--- /dev/null
@@ -0,0 +1,210 @@
+commit d5dd6189d506068ed11c8bfa1e1e9bffde04decd
+Author: Andreas Schwab <schwab@suse.de>
+Date:   Mon Jan 21 17:41:28 2013 +0100
+
+    Fix parsing of numeric hosts in gethostbyname_r
+
+diff --git a/nss/digits_dots.c b/nss/digits_dots.c
+index 2b86295..e007ef4 100644
+--- a/nss/digits_dots.c
++++ b/nss/digits_dots.c
+@@ -46,7 +46,10 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+     {
+       if (h_errnop)
+       *h_errnop = NETDB_INTERNAL;
+-      *result = NULL;
++      if (buffer_size == NULL)
++      *status = NSS_STATUS_TRYAGAIN;
++      else
++      *result = NULL;
+       return -1;
+     }
+@@ -83,14 +86,16 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+       }
+       size_needed = (sizeof (*host_addr)
+-                   + sizeof (*h_addr_ptrs) + strlen (name) + 1);
++                   + sizeof (*h_addr_ptrs)
++                   + sizeof (*h_alias_ptr) + strlen (name) + 1);
+       if (buffer_size == NULL)
+         {
+         if (buflen < size_needed)
+           {
++            *status = NSS_STATUS_TRYAGAIN;
+             if (h_errnop != NULL)
+-              *h_errnop = TRY_AGAIN;
++              *h_errnop = NETDB_INTERNAL;
+             __set_errno (ERANGE);
+             goto done;
+           }
+@@ -109,7 +114,7 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+             *buffer_size = 0;
+             __set_errno (save);
+             if (h_errnop != NULL)
+-              *h_errnop = TRY_AGAIN;
++              *h_errnop = NETDB_INTERNAL;
+             *result = NULL;
+             goto done;
+           }
+@@ -149,7 +154,9 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+                 if (! ok)
+                   {
+                     *h_errnop = HOST_NOT_FOUND;
+-                    if (buffer_size)
++                    if (buffer_size == NULL)
++                      *status = NSS_STATUS_NOTFOUND;
++                    else
+                       *result = NULL;
+                     goto done;
+                   }
+@@ -190,7 +197,7 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+                 if (buffer_size == NULL)
+                   *status = NSS_STATUS_SUCCESS;
+                 else
+-                 *result = resbuf;
++                  *result = resbuf;
+                 goto done;
+               }
+@@ -201,15 +208,6 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+       if ((isxdigit (name[0]) && strchr (name, ':') != NULL) || name[0] == ':')
+       {
+-        const char *cp;
+-        char *hostname;
+-        typedef unsigned char host_addr_t[16];
+-        host_addr_t *host_addr;
+-        typedef char *host_addr_list_t[2];
+-        host_addr_list_t *h_addr_ptrs;
+-        size_t size_needed;
+-        int addr_size;
+-
+         switch (af)
+           {
+           default:
+@@ -225,7 +223,10 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+             /* This is not possible.  We cannot represent an IPv6 address
+                in an `struct in_addr' variable.  */
+             *h_errnop = HOST_NOT_FOUND;
+-            *result = NULL;
++            if (buffer_size == NULL)
++              *status = NSS_STATUS_NOTFOUND;
++            else
++              *result = NULL;
+             goto done;
+           case AF_INET6:
+@@ -233,42 +234,6 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+             break;
+           }
+-        size_needed = (sizeof (*host_addr)
+-                       + sizeof (*h_addr_ptrs) + strlen (name) + 1);
+-
+-        if (buffer_size == NULL && buflen < size_needed)
+-          {
+-            if (h_errnop != NULL)
+-              *h_errnop = TRY_AGAIN;
+-            __set_errno (ERANGE);
+-            goto done;
+-          }
+-        else if (buffer_size != NULL && *buffer_size < size_needed)
+-          {
+-            char *new_buf;
+-            *buffer_size = size_needed;
+-            new_buf = realloc (*buffer, *buffer_size);
+-
+-            if (new_buf == NULL)
+-              {
+-                save = errno;
+-                free (*buffer);
+-                __set_errno (save);
+-                *buffer = NULL;
+-                *buffer_size = 0;
+-                *result = NULL;
+-                goto done;
+-              }
+-            *buffer = new_buf;
+-          }
+-
+-        memset (*buffer, '\0', size_needed);
+-
+-        host_addr = (host_addr_t *) *buffer;
+-        h_addr_ptrs = (host_addr_list_t *)
+-          ((char *) host_addr + sizeof (*host_addr));
+-        hostname = (char *) h_addr_ptrs + sizeof (*h_addr_ptrs);
+-
+         for (cp = name;; ++cp)
+           {
+             if (!*cp)
+@@ -281,7 +246,9 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+                 if (inet_pton (AF_INET6, name, host_addr) <= 0)
+                   {
+                     *h_errnop = HOST_NOT_FOUND;
+-                    if (buffer_size)
++                    if (buffer_size == NULL)
++                      *status = NSS_STATUS_NOTFOUND;
++                    else
+                       *result = NULL;
+                     goto done;
+                   }
+diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
+index 1067744..44d00f4 100644
+--- a/nss/getXXbyYY_r.c
++++ b/nss/getXXbyYY_r.c
+@@ -179,6 +179,9 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
+     case -1:
+       return errno;
+     case 1:
++#ifdef NEED_H_ERRNO
++      any_service = true;
++#endif
+       goto done;
+     }
+ #endif
+diff --git a/nss/test-digits-dots.c b/nss/test-digits-dots.c
+new file mode 100644
+index 0000000..1efa344
+--- /dev/null
++++ b/nss/test-digits-dots.c
+@@ -0,0 +1,38 @@
++/* Copyright (C) 2013 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library 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
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++/* Testcase for BZ #15014 */
++
++#include <stdlib.h>
++#include <netdb.h>
++#include <errno.h>
++
++static int
++do_test (void)
++{
++  char buf[32];
++  struct hostent *result = NULL;
++  struct hostent ret;
++  int h_err = 0;
++  int err;
++
++  err = gethostbyname_r ("1.2.3.4", &ret, buf, sizeof (buf), &result, &h_err);
++  return err == ERANGE && h_err == NETDB_INTERNAL ? EXIT_SUCCESS : EXIT_FAILURE;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
diff --git a/src/patches/glibc/glibc-rh995972.patch b/src/patches/glibc/glibc-rh995972.patch
new file mode 100644 (file)
index 0000000..0178bca
--- /dev/null
@@ -0,0 +1,246 @@
+commit d26dfc60edc8c6dd160eefff16a734152a835ca0
+Author: Martin von Gagern <Martin.vGagern@gmx.net>
+Date:   Sat May 14 21:25:43 2011 -0400
+
+    Fix handling of static TLS in dlopen'ed objects
+    
+    When dynamically loading a library along with several dependencies, calls to
+    _dl_add_to_slotinfo and _dl_update_slotinfo can become intermixed. As a
+    consequence, _dl_update_slotinfo will update the generation counter of the dtv
+    although not all of the slots belonging to that generation have been added.
+    Subsequent calls to _dl_add_to_slotinfo will add more slots to the same
+    generation, for which no storage will be allocated, as the dtv generation
+    checks will claim no work is necessary. This will lead to uninitialized dtv
+    entries and will likely cause a SIGSEGV when thread local variables are
+    accessed.
+
+diff --git a/elf/Makefile b/elf/Makefile
+index 8d9657d..6efb86c 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -76,6 +76,7 @@ distribute   := rtld-Rules \
+                  tst-tlsmod12.c tst-tls10.h tst-alignmod.c tst-alignmod2.c \
+                  circlemod1.c circlemod1a.c circlemod2.c circlemod2a.c \
+                  circlemod3.c circlemod3a.c nodlopenmod2.c \
++                 tst-tls19mod1.c tst-tls19mod2.c tst-tls19mod3.c \
+                  tls-macros.h \
+                  reldep8mod1.c reldep8mod2.c reldep8mod3.c \
+                  nodel2mod1.c nodel2mod2.c nodel2mod3.c \
+@@ -194,7 +195,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
+        restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
+        circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
+        tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
+-       tst-tls16 tst-tls17 tst-tls18 tst-tls-dlinfo \
++       tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \
+        tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
+        tst-dlmodcount tst-dlopenrpath tst-deep1 \
+        tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
+@@ -240,6 +241,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+               $(patsubst %,tst-tlsmod17a%,$(tlsmod17a-suffixes)) \
+               tst-tlsmod17b \
+               $(patsubst %,tst-tlsmod18a%,$(tlsmod18a-suffixes)) \
++              tst-tls19mod1 tst-tls19mod2 tst-tls19mod3 \
+               circlemod1 circlemod1a circlemod2 circlemod2a \
+               circlemod3 circlemod3a \
+               reldep8mod1 reldep8mod2 reldep8mod3 \
+@@ -525,6 +527,8 @@ $(objpfx)tst-tlsmod13a.so: $(objpfx)tst-tlsmod13.so
+ # For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED
+ $(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so
+ $(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so
++$(objpfx)tst-tls19mod1.so: $(objpfx)tst-tls19mod2.so $(objpfx)tst-tls19mod3.so
++$(objpfx)tst-tls19mod3.so: $(objpfx)ld.so
+ $(objpfx)reldep8mod3.so: $(objpfx)reldep8mod1.so $(objpfx)reldep8mod2.so
+ $(objpfx)nodel2mod3.so: $(objpfx)nodel2mod1.so $(objpfx)nodel2mod2.so
+ $(objpfx)reldep9mod2.so: $(objpfx)reldep9mod1.so
+@@ -822,6 +826,9 @@ $(patsubst %,$(objpfx)%.os,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.os : t
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ -DN=$* -DNOT_IN_libc=1 $<
+ $(patsubst %,$(objpfx)tst-tlsmod18a%.so,$(tlsmod18a-suffixes)): $(objpfx)tst-tlsmod18a%.so: $(objpfx)ld.so
++$(objpfx)tst-tls19: $(libdl)
++$(objpfx)tst-tls19.out: $(objpfx)tst-tls19mod1.so
++
+ CFLAGS-tst-align.c = $(stack-align-test-flags)
+ CFLAGS-tst-align2.c = $(stack-align-test-flags)
+ CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index cf8e8cc..8d90b56 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -347,6 +347,7 @@ dl_open_worker (void *a)
+   /* If the file is not loaded now as a dependency, add the search
+      list of the newly loaded object to the scope.  */
+   bool any_tls = false;
++  unsigned int first_static_tls = new->l_searchlist.r_nlist;
+   for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
+     {
+       struct link_map *imap = new->l_searchlist.r_list[i];
+@@ -425,30 +426,9 @@ dl_open_worker (void *a)
+            might have to increase its size.  */
+         _dl_add_to_slotinfo (imap);
+-        if (imap->l_need_tls_init)
+-          {
+-            /* For static TLS we have to allocate the memory here
+-               and now.  This includes allocating memory in the DTV.
+-               But we cannot change any DTV other than our own. So,
+-               if we cannot guarantee that there is room in the DTV
+-               we don't even try it and fail the load.
+-
+-               XXX We could track the minimum DTV slots allocated in
+-               all threads.  */
+-            if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
+-              _dl_signal_error (0, "dlopen", NULL, N_("\
+-cannot load any more object with static TLS"));
+-
+-            imap->l_need_tls_init = 0;
+-#ifdef SHARED
+-            /* Update the slot information data for at least the
+-               generation of the DSO we are allocating data for.  */
+-            _dl_update_slotinfo (imap->l_tls_modid);
+-#endif
+-
+-            GL(dl_init_static_tls) (imap);
+-            assert (imap->l_need_tls_init == 0);
+-          }
++        if (imap->l_need_tls_init
++            && first_static_tls == new->l_searchlist.r_nlist)
++          first_static_tls = i;
+         /* We have to bump the generation counter.  */
+         any_tls = true;
+@@ -460,6 +440,40 @@ cannot load any more object with static TLS"));
+     _dl_fatal_printf (N_("\
+ TLS generation counter wrapped!  Please report this."));
++  /* We need a second pass for static tls data, because _dl_update_slotinfo
++     must not be run while calls to _dl_add_to_slotinfo are still pending. */
++  for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
++    {
++      struct link_map *imap = new->l_searchlist.r_list[i];
++
++      if (imap->l_need_tls_init
++        && ! imap->l_init_called
++        && imap->l_tls_blocksize > 0)
++      {
++        /* For static TLS we have to allocate the memory here and
++           now.  This includes allocating memory in the DTV.  But we
++           cannot change any DTV other than our own. So, if we
++           cannot guarantee that there is room in the DTV we don't
++           even try it and fail the load.
++
++           XXX We could track the minimum DTV slots allocated in
++           all threads.  */
++        if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
++          _dl_signal_error (0, "dlopen", NULL, N_("\
++cannot load any more object with static TLS"));
++
++        imap->l_need_tls_init = 0;
++#ifdef SHARED
++        /* Update the slot information data for at least the
++           generation of the DSO we are allocating data for.  */
++        _dl_update_slotinfo (imap->l_tls_modid);
++#endif
++
++        GL(dl_init_static_tls) (imap);
++        assert (imap->l_need_tls_init == 0);
++      }
++    }
++
+   /* Notify the debugger all new objects have been relocated.  */
+   if (relocation_in_progress)
+     LIBC_PROBE (rtld_reloc_complete, 3, args->nsid, r, new);
+diff --git a/elf/tst-tls19.c b/elf/tst-tls19.c
+new file mode 100644
+index 0000000..acbc1d6
+--- /dev/null
++++ b/elf/tst-tls19.c
+@@ -0,0 +1,27 @@
++// BZ 12453
++#include <stdio.h>
++#include <dlfcn.h>
++
++
++static int
++do_test (void)
++{
++  void* dl = dlopen ("tst-tls19mod1.so", RTLD_LAZY | RTLD_GLOBAL);
++  if (dl == NULL)
++    {
++      printf ("Error loading tst-tls19mod1.so: %s\n", dlerror ());
++      return 1;
++    }
++
++  int (*fn) (void) = dlsym (dl, "foo");
++  if (fn == NULL)
++    {
++      printf("Error obtaining symbol foo\n");
++      return 1;
++    }
++
++  return fn ();
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+diff --git a/elf/tst-tls19mod1.c b/elf/tst-tls19mod1.c
+new file mode 100644
+index 0000000..2790097
+--- /dev/null
++++ b/elf/tst-tls19mod1.c
+@@ -0,0 +1,15 @@
++#include <stdio.h>
++
++extern int bar (void);
++extern int baz (void);
++
++int
++foo (void)
++{
++  int v1 = bar ();
++  int v2 = baz ();
++
++  printf ("bar=%d, baz=%d\n", v1, v2);
++
++  return v1 != 666 || v2 != 42;
++}
+diff --git a/elf/tst-tls19mod2.c b/elf/tst-tls19mod2.c
+new file mode 100644
+index 0000000..cae702f
+--- /dev/null
++++ b/elf/tst-tls19mod2.c
+@@ -0,0 +1,13 @@
++static int __thread tbar __attribute__ ((tls_model ("initial-exec"))) = 666;
++
++void
++setter (int a)
++{
++  tbar = a;
++}
++
++int
++bar (void)
++{
++  return tbar;
++}
+diff --git a/elf/tst-tls19mod3.c b/elf/tst-tls19mod3.c
+new file mode 100644
+index 0000000..e7b2801
+--- /dev/null
++++ b/elf/tst-tls19mod3.c
+@@ -0,0 +1,16 @@
++#include <stdio.h>
++
++static int __thread tbaz __attribute__ ((tls_model ("local-dynamic"))) = 42;
++
++void
++setter2 (int a)
++{
++  tbaz = a;
++}
++
++int
++baz (void)
++{
++  printf ("&tbaz=%p\n", &tbaz);
++  return tbaz;
++}
diff --git a/src/patches/linux-3.14.x-lamobo-r1.patch b/src/patches/linux-3.14.x-lamobo-r1.patch
new file mode 100644 (file)
index 0000000..4e604df
--- /dev/null
@@ -0,0 +1,5732 @@
+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 */
diff --git a/src/patches/strongswan-5.1.2-5.2.1_modp_custom.patch b/src/patches/strongswan-5.1.2-5.2.1_modp_custom.patch
new file mode 100644 (file)
index 0000000..df2cb09
--- /dev/null
@@ -0,0 +1,164 @@
+From a78ecdd47509626711a13481f53696e01d4b8c62 Mon Sep 17 00:00:00 2001
+From: Tobias Brunner <tobias@strongswan.org>
+Date: Mon, 1 Dec 2014 17:21:59 +0100
+Subject: [PATCH] crypto: Define MODP_CUSTOM outside of IKE DH range
+
+Before this fix it was possible to crash charon with an IKE_SA_INIT
+message containing a KE payload with DH group MODP_CUSTOM(1025).
+Defining MODP_CUSTOM outside of the two byte IKE DH identifier range
+prevents it from getting negotiated.
+
+Fixes CVE-2014-9221 in version 5.1.2 and newer.
+---
+ src/charon-tkm/src/tkm/tkm_diffie_hellman.c                   |  2 +-
+ src/libstrongswan/crypto/diffie_hellman.c                     | 11 ++++++-----
+ src/libstrongswan/crypto/diffie_hellman.h                     |  6 ++++--
+ src/libstrongswan/plugins/gcrypt/gcrypt_dh.c                  |  2 +-
+ src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c            |  2 +-
+ src/libstrongswan/plugins/ntru/ntru_ke.c                      |  2 +-
+ src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c    |  2 +-
+ src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c |  2 +-
+ src/libstrongswan/plugins/pkcs11/pkcs11_dh.c                  |  2 +-
+ 9 files changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/src/charon-tkm/src/tkm/tkm_diffie_hellman.c b/src/charon-tkm/src/tkm/tkm_diffie_hellman.c
+index 67db5e6d87d6..836e0b7f088d 100644
+--- a/src/charon-tkm/src/tkm/tkm_diffie_hellman.c
++++ b/src/charon-tkm/src/tkm/tkm_diffie_hellman.c
+@@ -41,7 +41,7 @@ struct private_tkm_diffie_hellman_t {
+       /**
+        * Diffie Hellman group number.
+        */
+-      u_int16_t group;
++      diffie_hellman_group_t group;
+       /**
+        * Diffie Hellman public value.
+diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c
+index bada1c529951..ac106e9c4d45 100644
+--- a/src/libstrongswan/crypto/diffie_hellman.c
++++ b/src/libstrongswan/crypto/diffie_hellman.c
+@@ -42,15 +42,16 @@ ENUM_NEXT(diffie_hellman_group_names, MODP_1024_160, ECP_512_BP, ECP_521_BIT,
+       "ECP_256_BP",
+       "ECP_384_BP",
+       "ECP_512_BP");
+-ENUM_NEXT(diffie_hellman_group_names, MODP_NULL, MODP_CUSTOM, ECP_512_BP,
+-      "MODP_NULL",
+-      "MODP_CUSTOM");
+-ENUM_NEXT(diffie_hellman_group_names, NTRU_112_BIT, NTRU_256_BIT, MODP_CUSTOM,
++ENUM_NEXT(diffie_hellman_group_names, MODP_NULL, MODP_NULL, ECP_512_BP,
++      "MODP_NULL");
++ENUM_NEXT(diffie_hellman_group_names, NTRU_112_BIT, NTRU_256_BIT, MODP_NULL,
+       "NTRU_112",
+       "NTRU_128",
+       "NTRU_192",
+       "NTRU_256");
+-ENUM_END(diffie_hellman_group_names, NTRU_256_BIT);
++ENUM_NEXT(diffie_hellman_group_names, MODP_CUSTOM, MODP_CUSTOM, NTRU_256_BIT,
++      "MODP_CUSTOM");
++ENUM_END(diffie_hellman_group_names, MODP_CUSTOM);
+ /**
+diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h
+index 105db22f14d4..d5161d077bb2 100644
+--- a/src/libstrongswan/crypto/diffie_hellman.h
++++ b/src/libstrongswan/crypto/diffie_hellman.h
+@@ -63,12 +63,14 @@ enum diffie_hellman_group_t {
+       /** insecure NULL diffie hellman group for testing, in PRIVATE USE */
+       MODP_NULL = 1024,
+       /** MODP group with custom generator/prime */
+-      MODP_CUSTOM = 1025,
+       /** Parameters defined by IEEE 1363.1, in PRIVATE USE */
+       NTRU_112_BIT = 1030,
+       NTRU_128_BIT = 1031,
+       NTRU_192_BIT = 1032,
+-      NTRU_256_BIT = 1033
++      NTRU_256_BIT = 1033,
++      /** internally used DH group with additional parameters g and p, outside
++       * of PRIVATE USE (i.e. IKEv2 DH group range) so it can't be negotiated */
++      MODP_CUSTOM = 65536,
+ };
+ /**
+diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c b/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c
+index f418b941db86..299865da2e09 100644
+--- a/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c
++++ b/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c
+@@ -35,7 +35,7 @@ struct private_gcrypt_dh_t {
+       /**
+        * Diffie Hellman group number
+        */
+-      u_int16_t group;
++      diffie_hellman_group_t group;
+       /*
+        * Generator value
+diff --git a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c
+index b74d35169f44..9936f7e4518f 100644
+--- a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c
++++ b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c
+@@ -42,7 +42,7 @@ struct private_gmp_diffie_hellman_t {
+       /**
+        * Diffie Hellman group number.
+        */
+-      u_int16_t group;
++      diffie_hellman_group_t group;
+       /*
+        * Generator value.
+diff --git a/src/libstrongswan/plugins/ntru/ntru_ke.c b/src/libstrongswan/plugins/ntru/ntru_ke.c
+index abaa22336221..e64f32b91d0e 100644
+--- a/src/libstrongswan/plugins/ntru/ntru_ke.c
++++ b/src/libstrongswan/plugins/ntru/ntru_ke.c
+@@ -56,7 +56,7 @@ struct private_ntru_ke_t {
+       /**
+        * Diffie Hellman group number.
+        */
+-      u_int16_t group;
++      diffie_hellman_group_t group;
+       /**
+        * NTRU Parameter Set
+diff --git a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
+index ff3382473666..1e68ac59b838 100644
+--- a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
++++ b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
+@@ -38,7 +38,7 @@ struct private_openssl_diffie_hellman_t {
+       /**
+        * Diffie Hellman group number.
+        */
+-      u_int16_t group;
++      diffie_hellman_group_t group;
+       /**
+        * Diffie Hellman object
+diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c
+index b487d59a59a3..50853d6f0bde 100644
+--- a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c
++++ b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c
+@@ -40,7 +40,7 @@ struct private_openssl_ec_diffie_hellman_t {
+       /**
+        * Diffie Hellman group number.
+        */
+-      u_int16_t group;
++      diffie_hellman_group_t group;
+       /**
+        * EC private (public) key
+diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c b/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c
+index 36cc284bf2b5..23b63d2386af 100644
+--- a/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c
++++ b/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c
+@@ -47,7 +47,7 @@ struct private_pkcs11_dh_t {
+       /**
+        * Diffie Hellman group number.
+        */
+-      u_int16_t group;
++      diffie_hellman_group_t group;
+       /**
+        * Handle for own private value
+-- 
+1.9.1
+