Merge branch 'next' of ssh://git.ipfire.org/pub/git/ipfire-2.x into next
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 15 Feb 2014 17:42:37 +0000 (18:42 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 15 Feb 2014 17:42:37 +0000 (18:42 +0100)
52 files changed:
config/kernel/kernel.config.armv5tel-ipfire-multi
config/kernel/kernel.config.i586-ipfire
config/kernel/kernel.config.i586-ipfire-pae
config/rootfiles/common/i586/linux
config/rootfiles/packages/linux-pae
config/u-boot/boot.scr
config/u-boot/boot.script
html/cgi-bin/atm-status.cgi
lfs/linux
src/initscripts/init.d/leds
src/patches/grsecurity-haswell-32bit-fix.patch [deleted file]
src/patches/kernel/omap/0002-omap2-twl-common-Add-default-power-configuration.patch [new file with mode: 0644]
src/patches/kernel/omap/3isp/0001-omap3isp-Use-the-common-clock-framework.patch [new file with mode: 0644]
src/patches/kernel/omap/3isp/0002-mt9m032-Fix-PLL-setup.patch [new file with mode: 0644]
src/patches/kernel/omap/3isp/0003-mt9m032-Define-MT9M032_READ_MODE1-bits.patch [new file with mode: 0644]
src/patches/kernel/omap/3isp/0004-mt9p031-Use-devm_-managed-helpers.patch [new file with mode: 0644]
src/patches/kernel/omap/3isp/0005-mt9p031-Add-support-for-regulators.patch [new file with mode: 0644]
src/patches/kernel/omap/3isp/0006-mt9p031-Use-the-common-clock-framework.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/0001-meego-modedb-add-Toshiba-LTA070B220F-800x480-support.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/0002-backlight-Add-TLC59108-backlight-control-driver.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/0003-tlc59108-adjust-for-beagleboard-uLCD7.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/0004-zeroMAP-Open-your-eyes.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/0005-ARM-OMAP-Beagle-use-TWL4030-generic-reset-script.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/0006-DSS2-use-DSI-PLL-for-DPI-with-OMAP3.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0001-Beagle-expansion-add-buddy-param-for-expansionboard-.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0002-Beagle-expansion-add-zippy.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0003-Beagle-expansion-add-zippy2.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0004-Beagle-expansion-add-trainer.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0005-Beagle-expansion-add-CircuitCo-ulcd-Support.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0006-Beagle-expansion-add-wifi.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0007-Beagle-expansion-add-beaglefpga.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0008-Beagle-expansion-add-spidev.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0009-Beagle-expansion-add-Aptina-li5m03-camera.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0010-Beagle-expansion-add-LSR-COM6L-Adapter-Board.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0011-Beagle-expansion-LSR-COM6L-Adapter-Board-also-initia.patch [new file with mode: 0644]
src/patches/kernel/omap/beagle/expansion/0011-WIP-Beagle-expansion-extend-spidev-to-uart2.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0001-panda-fix-wl12xx-regulator.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0002-ti-st-st-kim-fixing-firmware-path.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0003-Panda-expansion-add-spidev.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0004-HACK-PandaES-disable-cpufreq-so-board-will-boot.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0006-ARM-hw_breakpoint-Enable-debug-powerdown-only-if-sys.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0007-Revert-regulator-twl-Remove-TWL6030_FIXED_RESOURCE.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0008-Revert-regulator-twl-Remove-another-unused-variable-.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0009-Revert-regulator-twl-Remove-references-to-the-twl403.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0010-Revert-regulator-twl-Remove-references-to-32kHz-cloc.patch [new file with mode: 0644]
src/patches/kernel/omap/panda/0011-panda-spidev-setup-pinmux.patch [new file with mode: 0644]
src/patches/kernel/omap/sakoman/0001-OMAP-DSS2-add-bootarg-for-selecting-svideo.patch [new file with mode: 0644]
src/patches/kernel/omap/sakoman/0002-video-add-timings-for-hd720.patch [new file with mode: 0644]
src/patches/kernel/omap/sgx/0001-arm-Export-cache-flush-management-symbols-when-MULTI.patch [new file with mode: 0644]
src/patches/linux-3.10.25-imq.patch [deleted file]
src/patches/linux-3.10.30-imq.patch [new file with mode: 0644]
src/patches/linux-3.10.30_cs5535audio_fix_logspam_on_geos.patch [new file with mode: 0644]

index 128742d..d35e569 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/arm 3.10.27-ipfire-multi Kernel Configuration
+# Linux/arm 3.10.29-ipfire-multi Kernel Configuration
 #
 CONFIG_ARM=y
 CONFIG_MIGHT_HAVE_PCI=y
@@ -649,7 +649,7 @@ CONFIG_GENERIC_CPUFREQ_CPU0=y
 CONFIG_ARM_IMX6Q_CPUFREQ=m
 # CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
 CONFIG_ARM_OMAP2PLUS_CPUFREQ=y
-CONFIG_CPU_IDLE=y
+# CONFIG_CPU_IDLE is not set
 CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y
 CONFIG_CPU_IDLE_GOV_LADDER=y
 CONFIG_CPU_IDLE_GOV_MENU=y
@@ -3631,6 +3631,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_BACKLIGHT_LM3639 is not set
 # CONFIG_BACKLIGHT_LP855X is not set
 # CONFIG_BACKLIGHT_PANDORA is not set
+# CONFIG_BACKLIGHT_TLC59108 is not set
 
 #
 # Console display driver support
@@ -4926,35 +4927,10 @@ CONFIG_STRICT_DEVMEM=y
 CONFIG_ARM_UNWIND=y
 CONFIG_OLD_MCOUNT=y
 # CONFIG_DEBUG_USER is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ZYNQ_UART0 is not set
-# CONFIG_DEBUG_ZYNQ_UART1 is not set
-# CONFIG_DEBUG_IMX51_UART is not set
-# CONFIG_DEBUG_IMX53_UART is not set
-# CONFIG_DEBUG_IMX6Q_UART is not set
-CONFIG_DEBUG_OMAP2PLUS_UART=y
-# CONFIG_DEBUG_VEXPRESS_UART0_DETECT is not set
-# CONFIG_DEBUG_VEXPRESS_UART0_CA9 is not set
-# CONFIG_DEBUG_VEXPRESS_UART0_RS1 is not set
-# CONFIG_DEBUG_VT8500_UART0 is not set
-# CONFIG_DEBUG_ICEDCC is not set
-# CONFIG_DEBUG_SEMIHOSTING is not set
+# CONFIG_DEBUG_LL is not set
 CONFIG_DEBUG_IMX_UART_PORT=1
-# CONFIG_DEBUG_OMAP2UART1 is not set
-# CONFIG_DEBUG_OMAP2UART2 is not set
-# CONFIG_DEBUG_OMAP2UART3 is not set
-# CONFIG_DEBUG_OMAP3UART3 is not set
-CONFIG_DEBUG_OMAP4UART3=y
-# CONFIG_DEBUG_OMAP3UART4 is not set
-# CONFIG_DEBUG_OMAP4UART4 is not set
-# CONFIG_DEBUG_TI81XXUART1 is not set
-# CONFIG_DEBUG_TI81XXUART2 is not set
-# CONFIG_DEBUG_TI81XXUART3 is not set
-# CONFIG_DEBUG_AM33XXUART1 is not set
-# CONFIG_DEBUG_ZOOM_UART is not set
-CONFIG_DEBUG_LL_INCLUDE="debug/omap2plus.S"
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
 CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
-CONFIG_EARLY_PRINTK=y
 CONFIG_OC_ETM=y
 # CONFIG_PID_IN_CONTEXTIDR is not set
 
index 925b0e0..8ac3bd2 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.10.11-ipfire Kernel Configuration
+# Linux/x86 3.10.30-ipfire Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -1093,7 +1093,7 @@ CONFIG_L2TP_V3=y
 CONFIG_L2TP_IP=m
 CONFIG_L2TP_ETH=m
 CONFIG_STP=y
-CONFIG_GARP=y
+CONFIG_GARP=m
 CONFIG_BRIDGE=y
 CONFIG_BRIDGE_IGMP_SNOOPING=y
 CONFIG_BRIDGE_VLAN_FILTERING=y
@@ -1524,6 +1524,7 @@ CONFIG_SCSI_HPTIOP=m
 CONFIG_SCSI_BUSLOGIC=m
 # CONFIG_SCSI_FLASHPOINT is not set
 CONFIG_VMWARE_PVSCSI=m
+CONFIG_HYPERV_STORAGE=m
 CONFIG_LIBFC=m
 CONFIG_LIBFCOE=m
 CONFIG_FCOE=m
@@ -1715,6 +1716,7 @@ CONFIG_BCACHE=m
 # CONFIG_BCACHE_DEBUG is not set
 # CONFIG_BCACHE_EDEBUG is not set
 # CONFIG_BCACHE_CLOSURES_DEBUG is not set
+CONFIG_BLK_DEV_DM_BUILTIN=y
 CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_DEBUG is not set
 CONFIG_DM_BUFIO=m
@@ -2297,6 +2299,7 @@ CONFIG_MWIFIEX_USB=m
 #
 # CONFIG_WAN is not set
 CONFIG_VMXNET3=m
+CONFIG_HYPERV_NET=m
 CONFIG_ISDN=y
 CONFIG_ISDN_I4L=m
 CONFIG_ISDN_PPP=y
@@ -2818,7 +2821,7 @@ CONFIG_GPIO_ICH=m
 #
 # PCI GPIO expanders:
 #
-# CONFIG_GPIO_CS5535 is not set
+CONFIG_GPIO_CS5535=m
 # CONFIG_GPIO_AMD8111 is not set
 # CONFIG_GPIO_LANGWELL is not set
 # CONFIG_GPIO_PCH is not set
@@ -3890,6 +3893,7 @@ CONFIG_FB_UDL=m
 # CONFIG_FB_MB862XX is not set
 # CONFIG_FB_BROADSHEET is not set
 # CONFIG_FB_AUO_K190X is not set
+CONFIG_FB_HYPERV=m
 # CONFIG_EXYNOS_VIDEO is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=m
@@ -3905,6 +3909,7 @@ CONFIG_BACKLIGHT_APPLE=m
 # CONFIG_BACKLIGHT_LM3630 is not set
 # CONFIG_BACKLIGHT_LM3639 is not set
 # CONFIG_BACKLIGHT_LP855X is not set
+# CONFIG_BACKLIGHT_OT200 is not set
 
 #
 # Console display driver support
@@ -4196,6 +4201,7 @@ CONFIG_HID_SPEEDLINK=m
 # CONFIG_HID_STEELSERIES is not set
 CONFIG_HID_SUNPLUS=m
 # CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_HYPERV_MOUSE is not set
 # CONFIG_HID_SMARTJOYPLUS is not set
 CONFIG_HID_TIVO=m
 CONFIG_HID_TOPSEED=m
@@ -4473,17 +4479,18 @@ CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_LM3530=m
 CONFIG_LEDS_LM3533=m
 CONFIG_LEDS_LM3642=m
-# CONFIG_LEDS_PCA9532 is not set
-# CONFIG_LEDS_GPIO is not set
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_PCA9532_GPIO=y
+CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_LP3944=m
 CONFIG_LEDS_LP55XX_COMMON=m
 CONFIG_LEDS_LP5521=m
 CONFIG_LEDS_LP5523=m
 CONFIG_LEDS_LP5562=m
 CONFIG_LEDS_CLEVO_MAIL=m
-# CONFIG_LEDS_PCA955X is not set
+CONFIG_LEDS_PCA955X=m
 CONFIG_LEDS_PCA9633=m
-# CONFIG_LEDS_BD2802 is not set
+CONFIG_LEDS_BD2802=m
 CONFIG_LEDS_INTEL_SS4200=m
 CONFIG_LEDS_LT3593=m
 CONFIG_LEDS_DELL_NETBOOKS=m
@@ -4623,7 +4630,6 @@ CONFIG_DMA_ACPI=y
 #
 # DMA Clients
 #
-CONFIG_NET_DMA=y
 CONFIG_ASYNC_TX_DMA=y
 # CONFIG_DMATEST is not set
 CONFIG_DCA=m
@@ -4652,7 +4658,9 @@ CONFIG_VIRTIO_MMIO=m
 #
 # Microsoft Hyper-V guest support
 #
-# CONFIG_HYPERV is not set
+CONFIG_HYPERV=m
+CONFIG_HYPERV_UTILS=m
+CONFIG_HYPERV_BALLOON=m
 CONFIG_STAGING=y
 CONFIG_ET131X=m
 CONFIG_SLICOSS=m
index fc619b8..44b5213 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.10.11-ipfire Kernel Configuration
+# Linux/x86 3.10.30-ipfire Kernel Configuration
 #
 # CONFIG_64BIT is not set
 CONFIG_X86_32=y
@@ -1105,7 +1105,7 @@ CONFIG_L2TP_V3=y
 CONFIG_L2TP_IP=m
 CONFIG_L2TP_ETH=m
 CONFIG_STP=y
-CONFIG_GARP=y
+CONFIG_GARP=m
 CONFIG_BRIDGE=y
 CONFIG_BRIDGE_IGMP_SNOOPING=y
 CONFIG_BRIDGE_VLAN_FILTERING=y
@@ -1537,6 +1537,7 @@ CONFIG_SCSI_HPTIOP=m
 CONFIG_SCSI_BUSLOGIC=m
 # CONFIG_SCSI_FLASHPOINT is not set
 CONFIG_VMWARE_PVSCSI=m
+CONFIG_HYPERV_STORAGE=m
 CONFIG_LIBFC=m
 CONFIG_LIBFCOE=m
 CONFIG_FCOE=m
@@ -1728,6 +1729,7 @@ CONFIG_BCACHE=m
 # CONFIG_BCACHE_DEBUG is not set
 # CONFIG_BCACHE_EDEBUG is not set
 # CONFIG_BCACHE_CLOSURES_DEBUG is not set
+CONFIG_BLK_DEV_DM_BUILTIN=y
 CONFIG_BLK_DEV_DM=y
 # CONFIG_DM_DEBUG is not set
 CONFIG_DM_BUFIO=m
@@ -2313,6 +2315,7 @@ CONFIG_MWIFIEX_USB=m
 CONFIG_XEN_NETDEV_FRONTEND=m
 CONFIG_XEN_NETDEV_BACKEND=m
 CONFIG_VMXNET3=m
+CONFIG_HYPERV_NET=m
 CONFIG_ISDN=y
 CONFIG_ISDN_I4L=m
 CONFIG_ISDN_PPP=y
@@ -3910,6 +3913,7 @@ CONFIG_XEN_FBDEV_FRONTEND=m
 # CONFIG_FB_MB862XX is not set
 # CONFIG_FB_BROADSHEET is not set
 # CONFIG_FB_AUO_K190X is not set
+CONFIG_FB_HYPERV=m
 # CONFIG_EXYNOS_VIDEO is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=m
@@ -4216,6 +4220,7 @@ CONFIG_HID_SPEEDLINK=m
 # CONFIG_HID_STEELSERIES is not set
 CONFIG_HID_SUNPLUS=m
 # CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_HYPERV_MOUSE is not set
 # CONFIG_HID_SMARTJOYPLUS is not set
 CONFIG_HID_TIVO=m
 CONFIG_HID_TOPSEED=m
@@ -4493,17 +4498,18 @@ CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_LM3530=m
 CONFIG_LEDS_LM3533=m
 CONFIG_LEDS_LM3642=m
-# CONFIG_LEDS_PCA9532 is not set
-# CONFIG_LEDS_GPIO is not set
+CONFIG_LEDS_PCA9532=m
+CONFIG_LEDS_PCA9532_GPIO=y
+CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_LP3944=m
 CONFIG_LEDS_LP55XX_COMMON=m
 CONFIG_LEDS_LP5521=m
 CONFIG_LEDS_LP5523=m
 CONFIG_LEDS_LP5562=m
 CONFIG_LEDS_CLEVO_MAIL=m
-# CONFIG_LEDS_PCA955X is not set
+CONFIG_LEDS_PCA955X=m
 CONFIG_LEDS_PCA9633=m
-# CONFIG_LEDS_BD2802 is not set
+CONFIG_LEDS_BD2802=m
 CONFIG_LEDS_INTEL_SS4200=m
 CONFIG_LEDS_LT3593=m
 CONFIG_LEDS_DELL_NETBOOKS=m
@@ -4643,7 +4649,6 @@ CONFIG_DMA_ACPI=y
 #
 # DMA Clients
 #
-CONFIG_NET_DMA=y
 CONFIG_ASYNC_TX_DMA=y
 # CONFIG_DMATEST is not set
 CONFIG_DCA=m
@@ -4672,7 +4677,9 @@ CONFIG_VIRTIO_MMIO=m
 #
 # Microsoft Hyper-V guest support
 #
-# CONFIG_HYPERV is not set
+CONFIG_HYPERV=m
+CONFIG_HYPERV_UTILS=m
+CONFIG_HYPERV_BALLOON=m
 
 #
 # Xen driver support
index d662516..3ec81ec 100644 (file)
@@ -281,6 +281,7 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/firmware/edd.ko
 #lib/modules/KVER-ipfire/kernel/drivers/firmware/iscsi_ibft.ko
 #lib/modules/KVER-ipfire/kernel/drivers/gpio
+#lib/modules/KVER-ipfire/kernel/drivers/gpio/gpio-cs5535.ko
 #lib/modules/KVER-ipfire/kernel/drivers/gpio/gpio-ich.ko
 #lib/modules/KVER-ipfire/kernel/drivers/gpio/gpio-sch.ko
 #lib/modules/KVER-ipfire/kernel/drivers/gpio/gpio-ts5500.ko
@@ -367,6 +368,10 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/hsi/clients
 #lib/modules/KVER-ipfire/kernel/drivers/hsi/clients/hsi_char.ko
 #lib/modules/KVER-ipfire/kernel/drivers/hsi/hsi.ko
+#lib/modules/KVER-ipfire/kernel/drivers/hv
+#lib/modules/KVER-ipfire/kernel/drivers/hv/hv_balloon.ko
+#lib/modules/KVER-ipfire/kernel/drivers/hv/hv_utils.ko
+#lib/modules/KVER-ipfire/kernel/drivers/hv/hv_vmbus.ko
 #lib/modules/KVER-ipfire/kernel/drivers/hwmon
 #lib/modules/KVER-ipfire/kernel/drivers/hwmon/abituguru.ko
 #lib/modules/KVER-ipfire/kernel/drivers/hwmon/abituguru3.ko
@@ -619,8 +624,10 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/isdn/mISDN/mISDN_dsp.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds
 #lib/modules/KVER-ipfire/kernel/drivers/leds/dell-led.ko
+#lib/modules/KVER-ipfire/kernel/drivers/leds/leds-bd2802.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-blinkm.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-clevo-mail.ko
+#lib/modules/KVER-ipfire/kernel/drivers/leds/leds-gpio.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-lm3530.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-lm3533.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-lm355x.ko
@@ -632,6 +639,8 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-lp55xx-common.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-lt3593.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-ot200.ko
+#lib/modules/KVER-ipfire/kernel/drivers/leds/leds-pca9532.ko
+#lib/modules/KVER-ipfire/kernel/drivers/leds/leds-pca955x.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-pca9633.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-ss4200.ko
 #lib/modules/KVER-ipfire/kernel/drivers/leds/leds-tca6507.ko
@@ -1505,6 +1514,8 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/net/ethernet/wiznet/w5300.ko
 #lib/modules/KVER-ipfire/kernel/drivers/net/ethernet/xircom
 #lib/modules/KVER-ipfire/kernel/drivers/net/ethernet/xircom/xirc2ps_cs.ko
+#lib/modules/KVER-ipfire/kernel/drivers/net/hyperv
+#lib/modules/KVER-ipfire/kernel/drivers/net/hyperv/hv_netvsc.ko
 #lib/modules/KVER-ipfire/kernel/drivers/net/ifb.ko
 #lib/modules/KVER-ipfire/kernel/drivers/net/imq.ko
 #lib/modules/KVER-ipfire/kernel/drivers/net/macvlan.ko
@@ -1867,7 +1878,7 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/scsi/gdth.ko
 #lib/modules/KVER-ipfire/kernel/drivers/scsi/hpsa.ko
 #lib/modules/KVER-ipfire/kernel/drivers/scsi/hptiop.ko
-#lib/modules/KVER-ipfire/kernel/drivers/scsi/imm.ko
+#lib/modules/KVER-ipfire/kernel/drivers/scsi/hv_storvsc.ko
 #lib/modules/KVER-ipfire/kernel/drivers/scsi/in2000.ko
 #lib/modules/KVER-ipfire/kernel/drivers/scsi/initio.ko
 #lib/modules/KVER-ipfire/kernel/drivers/scsi/ipr.ko
@@ -2118,6 +2129,7 @@ lib/modules/KVER-ipfire
 #lib/modules/KVER-ipfire/kernel/drivers/video/geode/gxfb.ko
 #lib/modules/KVER-ipfire/kernel/drivers/video/geode/lxfb.ko
 #lib/modules/KVER-ipfire/kernel/drivers/video/hgafb.ko
+#lib/modules/KVER-ipfire/kernel/drivers/video/hyperv_fb.ko
 #lib/modules/KVER-ipfire/kernel/drivers/video/i740fb.ko
 #lib/modules/KVER-ipfire/kernel/drivers/video/kyro
 #lib/modules/KVER-ipfire/kernel/drivers/video/kyro/kyrofb.ko
index a7eaf40..00677aa 100644 (file)
@@ -364,6 +364,10 @@ lib/modules/KVER-ipfire-pae
 #lib/modules/KVER-ipfire-pae/kernel/drivers/hsi/clients
 #lib/modules/KVER-ipfire-pae/kernel/drivers/hsi/clients/hsi_char.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/hsi/hsi.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/hv
+#lib/modules/KVER-ipfire-pae/kernel/drivers/hv/hv_balloon.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/hv/hv_utils.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/hv/hv_vmbus.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/hwmon
 #lib/modules/KVER-ipfire-pae/kernel/drivers/hwmon/abituguru.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/hwmon/abituguru3.ko
@@ -616,8 +620,10 @@ lib/modules/KVER-ipfire-pae
 #lib/modules/KVER-ipfire-pae/kernel/drivers/isdn/mISDN/mISDN_dsp.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/dell-led.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-bd2802.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-blinkm.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-clevo-mail.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-gpio.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-lm3530.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-lm3533.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-lm355x.ko
@@ -629,6 +635,8 @@ lib/modules/KVER-ipfire-pae
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-lp55xx-common.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-lt3593.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-ot200.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-pca9532.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-pca955x.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-pca9633.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-ss4200.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/leds/leds-tca6507.ko
@@ -1502,6 +1510,8 @@ lib/modules/KVER-ipfire-pae
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/ethernet/wiznet/w5300.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/ethernet/xircom
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/ethernet/xircom/xirc2ps_cs.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/net/hyperv
+#lib/modules/KVER-ipfire-pae/kernel/drivers/net/hyperv/hv_netvsc.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/ifb.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/imq.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/net/macvlan.ko
@@ -1868,6 +1878,7 @@ lib/modules/KVER-ipfire-pae
 #lib/modules/KVER-ipfire-pae/kernel/drivers/scsi/gdth.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/scsi/hpsa.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/scsi/hptiop.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/scsi/hv_storvsc.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/scsi/imm.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/scsi/in2000.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/scsi/initio.ko
@@ -2119,6 +2130,7 @@ lib/modules/KVER-ipfire-pae
 #lib/modules/KVER-ipfire-pae/kernel/drivers/video/geode/gxfb.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/video/geode/lxfb.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/video/hgafb.ko
+#lib/modules/KVER-ipfire-pae/kernel/drivers/video/hyperv_fb.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/video/i740fb.ko
 #lib/modules/KVER-ipfire-pae/kernel/drivers/video/kyro
 #lib/modules/KVER-ipfire-pae/kernel/drivers/video/kyro/kyrofb.ko
index 0d36a6b..672b152 100755 (executable)
Binary files a/config/u-boot/boot.scr and b/config/u-boot/boot.scr differ
index 49e6c9c..66d7628 100755 (executable)
@@ -1,7 +1,7 @@
 fatload mmc 0:1 0x82000000 zImage-ipfire-multi
 fatload mmc 0:1 0x85000000 uInit-ipfire-multi
 #fatload mmc 0:1 ${fdtaddr} omap4-${board_name}.dtb
-setenv bootargs vram=32M earlyprintk console=tty1 rootwait smsc95xx.macaddr=$usbethaddr root=/dev/mmcblk0p3 ro
+setenv bootargs video=800x600 console=tty1 rootwait smsc95xx.macaddr=$usbethaddr root=/dev/mmcblk0p3 ro
 # Pandaboard has serious Problems in dt mode with kernel 3.10.x
 #bootz 0x82000000 0x85000000 ${fdtaddr}
 bootz 0x82000000 0x85000000
index 5c0fa8b..c2a9914 100644 (file)
@@ -46,6 +46,27 @@ foreach (@modems){
        my $lines=0;
        print "<center><table>";
        my $modem=$_;
+       my @pfile = `grep . /sys/class/atm/$modem/parameters/* 2>/dev/null`;
+       foreach (@pfile){
+               chomp($_);
+               my $param= `echo $_ | cut -d'/' -f7 | cut -d':' -f1`;
+               my $value= `cat /sys/class/atm/$modem/parameters/$param`;
+               chomp($param);
+               chomp($value);
+               if (!($param =~"uevent") 
+                 && !($param =~"resource")
+                 && !($param eq "")
+               ) {
+                               
+                       $lines++;
+                       if ($lines % 2){
+                               print "<tr bgcolor='$color{'color22'}'>";
+                       }else{
+                               print "<tr bgcolor='$color{'color20'}'>";
+                       }
+                       print "<td align='left'>$param</td><td align='left'>$value</td> ";              
+               }
+       }
        my @pfile = `grep . /sys/class/atm/$modem/device/* 2>/dev/null`;
        foreach (@pfile){
                chomp($_);
@@ -58,6 +79,8 @@ foreach (@modems){
                  && !($param =~"bInterface")
                  && !($param =~"bAlternateSetting")
                  && !($param =~"bNumEndpoints")
+                 && !($param =~"config matches")
+                 && !($param =~"resource")
                  && !($param eq "")
                ) {
                                
index 08fa9a3..d460708 100644 (file)
--- a/lfs/linux
+++ b/lfs/linux
 
 include Config
 
-VER        = 3.10.29
+VER        = 3.10.30
 
 RPI_PATCHES = linux-3.10.27-grsec-943b563
-GRS_PATCHES = grsecurity-2.9.1-3.10.29-ipfire1.patch.xz
+GRS_PATCHES = grsecurity-2.9.1-3.10.30-ipfire1.patch.xz
 
 THISAPP    = linux-$(VER)
 DL_FILE    = linux-$(VER).tar.xz
@@ -36,7 +36,7 @@ DIR_APP    = $(DIR_SRC)/$(THISAPP)
 CFLAGS     =
 CXXFLAGS   =
 
-PAK_VER    = 34
+PAK_VER    = 35
 DEPS      = ""
 
 VERSUFIX=ipfire$(KCFG)
@@ -74,9 +74,9 @@ $(DL_FILE)                            = $(URL_IPFIRE)/$(DL_FILE)
 rpi-patches-$(RPI_PATCHES).patch.xz    = $(URL_IPFIRE)/rpi-patches-$(RPI_PATCHES).patch.xz
 $(GRS_PATCHES)                         = $(URL_IPFIRE)/$(GRS_PATCHES)
 
-$(DL_FILE)_MD5                         = 59e4f495b1302f2bca0e72d204c5fd0b
+$(DL_FILE)_MD5                         = f48ca7dd9f2eb14a2903cb6a4fbe07ed
 rpi-patches-$(RPI_PATCHES).patch.xz_MD5        = 8cf81f48408306d93ccee59b58af2e92
-$(GRS_PATCHES)_MD5                     = b39b69eb7439141621ecf0221b3bd29e
+$(GRS_PATCHES)_MD5                     = 044e29280d4717441e89e8d80abba563
 
 install : $(TARGET)
 
@@ -112,7 +112,7 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        ln -svf linux-$(VER) $(DIR_SRC)/linux
 
        # Linux Intermediate Queueing Device
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.25-imq.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.30-imq.patch
 
        # ipp2p 0.8.2-ipfire
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10-ipp2p-0.8.2-ipfire.patch
@@ -124,7 +124,6 @@ $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
 ifneq "$(KCFG)" "-headers"
        cd $(DIR_APP) && xz -c -d $(DIR_DL)/$(GRS_PATCHES) | patch -Np1
        cd $(DIR_APP) && rm localversion-grsec
-       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grsecurity-haswell-32bit-fix.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.7-disable-compat_vdso.patch
 endif
 
@@ -148,6 +147,9 @@ endif
        # Add LED trigger
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.9-ledtrig-netdev-1.patch
 
+       # cs5535audio spams syslog if no ac97 was present (geos router)
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.30_cs5535audio_fix_logspam_on_geos.patch
+
        # Fix uevent PHYSDEVDRIVER
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.2.33_ipg-fix-driver-name.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-2.6.32.27_mcs7830-fix-driver-name.patch
@@ -161,11 +163,41 @@ endif
 
 ifeq "$(KCFG)" "-multi"
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10.27-fs-exec-atomic64-operand-requires-impossible-reload.patch
-#      cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.2-0001-panda-wlan-fix.patch
-#      cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.2-0002-panda-i2c.patch
-#      cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.2-panda-reboot.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/linux-3.10-smsc95xx-add_mac_addr_param.patch
 
+       # Patchset for Omap (beagle/panda).
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/0002-omap2-twl-common-Add-default-power-configuration.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/sakoman/0001-OMAP-DSS2-add-bootarg-for-selecting-svideo.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/sakoman/0002-video-add-timings-for-hd720.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0001-Beagle-expansion-add-buddy-param-for-expansionboard-.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0002-Beagle-expansion-add-zippy.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0003-Beagle-expansion-add-zippy2.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0004-Beagle-expansion-add-trainer.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0005-Beagle-expansion-add-CircuitCo-ulcd-Support.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0006-Beagle-expansion-add-wifi.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0007-Beagle-expansion-add-beaglefpga.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0008-Beagle-expansion-add-spidev.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0009-Beagle-expansion-add-Aptina-li5m03-camera.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0010-Beagle-expansion-add-LSR-COM6L-Adapter-Board.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/expansion/0011-Beagle-expansion-LSR-COM6L-Adapter-Board-also-initia.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/0001-meego-modedb-add-Toshiba-LTA070B220F-800x480-support.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/0002-backlight-Add-TLC59108-backlight-control-driver.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/0003-tlc59108-adjust-for-beagleboard-uLCD7.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/0004-zeroMAP-Open-your-eyes.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/0005-ARM-OMAP-Beagle-use-TWL4030-generic-reset-script.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/beagle/0006-DSS2-use-DSI-PLL-for-DPI-with-OMAP3.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0001-panda-fix-wl12xx-regulator.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0002-ti-st-st-kim-fixing-firmware-path.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0003-Panda-expansion-add-spidev.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0004-HACK-PandaES-disable-cpufreq-so-board-will-boot.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0006-ARM-hw_breakpoint-Enable-debug-powerdown-only-if-sys.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0007-Revert-regulator-twl-Remove-TWL6030_FIXED_RESOURCE.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0008-Revert-regulator-twl-Remove-another-unused-variable-.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0009-Revert-regulator-twl-Remove-references-to-the-twl403.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0010-Revert-regulator-twl-Remove-references-to-32kHz-cloc.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/panda/0011-panda-spidev-setup-pinmux.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/omap/sgx/0001-arm-Export-cache-flush-management-symbols-when-MULTI.patch
+
        # Patchset for Wandboard.
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/dts/0001-imx6qdl-wandboard-dts-backport.patch
        cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/kernel/wandboard/dts/0002-ARM-dts-imx6qdl-wandboard-add-gpio-lines-to-wandboar.patch
index 3bd27a4..52ef270 100644 (file)
@@ -50,6 +50,14 @@ disable_led_trigger ()
        fi
 }
 
+# enable LED
+enable_led ()
+{
+       if [ -d "/sys/class/leds/$1" ]; then
+               echo "1" >        /sys/class/leds/$1/brightness
+       fi
+}
+
 case "${1}" in
        start)
                # Alix LED start
@@ -57,6 +65,11 @@ case "${1}" in
                setup_netdev_trigger alix:2 ${RED_DEV} rx
                setup_netdev_trigger alix:3 ${RED_DEV} tx
 
+               # Geos LED start
+               setup_heartbeat_trigger geos:1
+               setup_netdev_trigger geos:2 ${RED_DEV} rx
+               setup_netdev_trigger geos:3 ${RED_DEV} tx
+
                # Dreamplug
                setup_netdev_trigger dreamplug:green:wlan ${GREEN_DEV} tx rx
                setup_netdev_trigger dreamplug:blue:wlanap ${BLUE_DEV} tx rx
@@ -80,9 +93,16 @@ case "${1}" in
        stop)
                # Alix LED stop
                disable_led_trigger alix:1
+               enable_led alix:1
                disable_led_trigger alix:2
                disable_led_trigger alix:3
 
+               # Geos LED stop
+               disable_led_trigger geos:1
+               enable_led geos:1
+               disable_led_trigger geos:2
+               disable_led_trigger geos:3
+
                # Dreamplug
                disable_led_trigger dreamplug:green:wlan
                disable_led_trigger dreamplug:blue:wlanap
diff --git a/src/patches/grsecurity-haswell-32bit-fix.patch b/src/patches/grsecurity-haswell-32bit-fix.patch
deleted file mode 100644 (file)
index abff2b0..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
-index 7430027..2124e35 100644
---- a/arch/x86/include/asm/mmu_context.h
-+++ b/arch/x86/include/asm/mmu_context.h
-@@ -80,7 +80,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
- #if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF)
-               if (static_cpu_has(X86_FEATURE_PCID)) {
-                       if (static_cpu_has(X86_FEATURE_INVPCID)) {
--                              unsigned long descriptor[2];
-+                              u64 descriptor[2];
-                               descriptor[0] = PCID_USER;
-                               asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_SINGLE_CONTEXT) : "memory");
-                       } else {
-@@ -144,7 +144,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
- #if defined(CONFIG_X86_64) && defined(CONFIG_PAX_MEMORY_UDEREF)
-               if (static_cpu_has(X86_FEATURE_PCID)) {
-                       if (static_cpu_has(X86_FEATURE_INVPCID)) {
--                              unsigned long descriptor[2];
-+                              u64 descriptor[2];
-                               descriptor[0] = PCID_USER;
-                               asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_SINGLE_CONTEXT) : "memory");
-                       } else {
-diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
-index 45844c0..ada2172 100644
---- a/arch/x86/include/asm/tlbflush.h
-+++ b/arch/x86/include/asm/tlbflush.h
-@@ -18,7 +18,7 @@
- static inline void __native_flush_tlb(void)
- {
-       if (static_cpu_has(X86_FEATURE_INVPCID)) {
--              unsigned long descriptor[2];
-+              u64 descriptor[2];
-               descriptor[0] = PCID_KERNEL;
-               asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_ALL_MONGLOBAL) : "memory");
-@@ -42,7 +42,7 @@ static inline void __native_flush_tlb(void)
- static inline void __native_flush_tlb_global_irq_disabled(void)
- {
-       if (static_cpu_has(X86_FEATURE_INVPCID)) {
--              unsigned long descriptor[2];
-+              u64 descriptor[2];
-               descriptor[0] = PCID_KERNEL;
-               asm volatile(__ASM_INVPCID : : "d"(&descriptor), "a"(INVPCID_ALL_GLOBAL) : "memory");
-@@ -77,7 +77,7 @@ static inline void __native_flush_tlb_single(unsigned long addr)
- {
-       if (static_cpu_has(X86_FEATURE_INVPCID)) {
--              unsigned long descriptor[2];
-+              u64 descriptor[2];
-               descriptor[0] = PCID_KERNEL;
-               descriptor[1] = addr;
diff --git a/src/patches/kernel/omap/0002-omap2-twl-common-Add-default-power-configuration.patch b/src/patches/kernel/omap/0002-omap2-twl-common-Add-default-power-configuration.patch
new file mode 100644 (file)
index 0000000..d27ad54
--- /dev/null
@@ -0,0 +1,88 @@
+From 2e908aeebd6804296e7d14a96de6be1e2de38e93 Mon Sep 17 00:00:00 2001
+From: Matthias Brugger <matthias.bgg@gmail.com>
+Date: Wed, 23 Jan 2013 19:50:38 +0100
+Subject: [PATCH 2/2] omap2: twl-common: Add default power configuration
+
+This patch adds a generic power script configuration.
+When rebooting an OMAP3530 at 125 MHz, the reboot hangs.
+With the generic power script, TWL4030 will be reset
+when a warm reset occures. This way the OMAP3530 does not
+hang on reboot.
+
+Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
+---
+ arch/arm/mach-omap2/twl-common.c |   38 ++++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-omap2/twl-common.h |    1 +
+ 2 files changed, 39 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
+index e49b40b..f096beb 100644
+--- a/arch/arm/mach-omap2/twl-common.c
++++ b/arch/arm/mach-omap2/twl-common.c
+@@ -120,6 +120,41 @@ static struct twl4030_audio_data omap3_audio_pdata = {
+       .codec = &omap3_codec,
+ };
++static struct twl4030_ins wrst_seq[] __initdata = {
++      {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
++      {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
++      {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
++      {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
++      {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
++      {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
++};
++
++static struct twl4030_script wrst_script __initdata = {
++      .script = wrst_seq,
++      .size   = ARRAY_SIZE(wrst_seq),
++      .flags  = TWL4030_WRST_SCRIPT,
++};
++
++static struct twl4030_script *omap3_power_scripts[] __initdata = {
++      &wrst_script,
++};
++
++static struct twl4030_resconfig omap3_rconfig[] = {
++      { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3, .type = -1,
++              .type2 = -1 },
++      { .resource = RES_VDD1, .devgroup = DEV_GRP_P1, .type = -1,
++              .type2 = -1 },
++      { .resource = RES_VDD2, .devgroup = DEV_GRP_P1, .type = -1,
++              .type2 = -1 },
++      { 0, 0},
++};
++
++static struct twl4030_power_data omap3_power_pdata = {
++      .scripts        = omap3_power_scripts,
++      .num            = ARRAY_SIZE(omap3_power_scripts),
++      .resource_config = omap3_rconfig,
++};
++
+ static struct regulator_consumer_supply omap3_vdda_dac_supplies[] = {
+       REGULATOR_SUPPLY("vdda_dac", "omapdss_venc"),
+ };
+@@ -224,6 +259,9 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
+       if (pdata_flags & TWL_COMMON_PDATA_AUDIO && !pmic_data->audio)
+               pmic_data->audio = &omap3_audio_pdata;
++      if (pdata_flags & TWL_COMMON_PDATA_POWER && !pmic_data->power)
++              pmic_data->power = &omap3_power_pdata;
++
+       /* Common regulator configurations */
+       if (regulators_flags & TWL_COMMON_REGULATOR_VDAC && !pmic_data->vdac)
+               pmic_data->vdac = &omap3_vdac_idata;
+diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h
+index dcfbad5..dbeb905 100644
+--- a/arch/arm/mach-omap2/twl-common.h
++++ b/arch/arm/mach-omap2/twl-common.h
+@@ -7,6 +7,7 @@
+ #define TWL_COMMON_PDATA_BCI          (1 << 1)
+ #define TWL_COMMON_PDATA_MADC         (1 << 2)
+ #define TWL_COMMON_PDATA_AUDIO                (1 << 3)
++#define TWL_COMMON_PDATA_POWER                (1 << 4)
+ /* Common LDO regulators for TWL4030/TWL6030 */
+ #define TWL_COMMON_REGULATOR_VDAC     (1 << 0)
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/3isp/0001-omap3isp-Use-the-common-clock-framework.patch b/src/patches/kernel/omap/3isp/0001-omap3isp-Use-the-common-clock-framework.patch
new file mode 100644 (file)
index 0000000..a61d5b8
--- /dev/null
@@ -0,0 +1,444 @@
+From 369b60c157f67a71a6f302ab9843ae2de1805a2a Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Mon, 22 Oct 2012 15:43:00 +0200
+Subject: [PATCH 1/6] omap3isp: Use the common clock framework
+
+Expose the two ISP external clocks XCLKA and XCLKB as common clocks for
+subdev drivers.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Acked-by: Mike Turquette <mturquette@linaro.org>
+---
+ drivers/media/platform/omap3isp/isp.c |  277 ++++++++++++++++++++++++---------
+ drivers/media/platform/omap3isp/isp.h |   22 ++-
+ include/media/omap3isp.h              |   10 +-
+ 3 files changed, 225 insertions(+), 84 deletions(-)
+
+diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
+index 6e5ad8e..1d7dbd5 100644
+--- a/drivers/media/platform/omap3isp/isp.c
++++ b/drivers/media/platform/omap3isp/isp.c
+@@ -55,6 +55,7 @@
+ #include <asm/cacheflush.h>
+ #include <linux/clk.h>
++#include <linux/clkdev.h>
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+@@ -148,6 +149,201 @@ void omap3isp_flush(struct isp_device *isp)
+       isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+ }
++/* -----------------------------------------------------------------------------
++ * XCLK
++ */
++
++#define to_isp_xclk(_hw)      container_of(_hw, struct isp_xclk, hw)
++
++static void isp_xclk_update(struct isp_xclk *xclk, u32 divider)
++{
++      switch (xclk->id) {
++      case ISP_XCLK_A:
++              isp_reg_clr_set(xclk->isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
++                              ISPTCTRL_CTRL_DIVA_MASK,
++                              divider << ISPTCTRL_CTRL_DIVA_SHIFT);
++              break;
++      case ISP_XCLK_B:
++              isp_reg_clr_set(xclk->isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
++                              ISPTCTRL_CTRL_DIVB_MASK,
++                              divider << ISPTCTRL_CTRL_DIVB_SHIFT);
++              break;
++      }
++}
++
++static int isp_xclk_prepare(struct clk_hw *hw)
++{
++      struct isp_xclk *xclk = to_isp_xclk(hw);
++
++      omap3isp_get(xclk->isp);
++
++      return 0;
++}
++
++static void isp_xclk_unprepare(struct clk_hw *hw)
++{
++      struct isp_xclk *xclk = to_isp_xclk(hw);
++
++      omap3isp_put(xclk->isp);
++}
++
++static int isp_xclk_enable(struct clk_hw *hw)
++{
++      struct isp_xclk *xclk = to_isp_xclk(hw);
++      unsigned long flags;
++
++      spin_lock_irqsave(&xclk->lock, flags);
++      isp_xclk_update(xclk, xclk->divider);
++      xclk->enabled = true;
++      spin_unlock_irqrestore(&xclk->lock, flags);
++
++      return 0;
++}
++
++static void isp_xclk_disable(struct clk_hw *hw)
++{
++      struct isp_xclk *xclk = to_isp_xclk(hw);
++      unsigned long flags;
++
++      spin_lock_irqsave(&xclk->lock, flags);
++      isp_xclk_update(xclk, 0);
++      xclk->enabled = false;
++      spin_unlock_irqrestore(&xclk->lock, flags);
++}
++
++static unsigned long isp_xclk_recalc_rate(struct clk_hw *hw,
++                                        unsigned long parent_rate)
++{
++      struct isp_xclk *xclk = to_isp_xclk(hw);
++
++      return parent_rate / xclk->divider;
++}
++
++static u32 isp_xclk_calc_divider(unsigned long *rate, unsigned long parent_rate)
++{
++      u32 divider;
++
++      if (*rate >= parent_rate) {
++              *rate = parent_rate;
++              return ISPTCTRL_CTRL_DIV_BYPASS;
++      }
++
++      divider = DIV_ROUND_CLOSEST(parent_rate, *rate);
++      if (divider >= ISPTCTRL_CTRL_DIV_BYPASS)
++              divider = ISPTCTRL_CTRL_DIV_BYPASS - 1;
++
++      *rate = parent_rate / divider;
++      return divider;
++}
++
++static long isp_xclk_round_rate(struct clk_hw *hw, unsigned long rate,
++                              unsigned long *parent_rate)
++{
++      isp_xclk_calc_divider(&rate, *parent_rate);
++      return rate;
++}
++
++static int isp_xclk_set_rate(struct clk_hw *hw, unsigned long rate,
++                           unsigned long parent_rate)
++{
++      struct isp_xclk *xclk = to_isp_xclk(hw);
++      unsigned long flags;
++      u32 divider;
++
++      divider = isp_xclk_calc_divider(&rate, parent_rate);
++
++      spin_lock_irqsave(&xclk->lock, flags);
++
++      xclk->divider = divider;
++      if (xclk->enabled)
++              isp_xclk_update(xclk, divider);
++
++      spin_unlock_irqrestore(&xclk->lock, flags);
++
++      dev_dbg(xclk->isp->dev, "%s: cam_xclk%c set to %lu Hz (div %u)\n",
++              __func__, xclk->id == ISP_XCLK_A ? 'a' : 'b', rate, divider);
++      return 0;
++}
++
++static const struct clk_ops isp_xclk_ops = {
++      .prepare = isp_xclk_prepare,
++      .unprepare = isp_xclk_unprepare,
++      .enable = isp_xclk_enable,
++      .disable = isp_xclk_disable,
++      .recalc_rate = isp_xclk_recalc_rate,
++      .round_rate = isp_xclk_round_rate,
++      .set_rate = isp_xclk_set_rate,
++};
++
++static const char *isp_xclk_parent_name = "cam_mclk";
++
++static const struct clk_init_data isp_xclk_init_data = {
++      .name = "cam_xclk",
++      .ops = &isp_xclk_ops,
++      .parent_names = &isp_xclk_parent_name,
++      .num_parents = 1,
++};
++
++static int isp_xclk_init(struct isp_device *isp)
++{
++      struct isp_platform_data *pdata = isp->pdata;
++      struct clk_init_data init;
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) {
++              struct isp_xclk *xclk = &isp->xclks[i];
++              struct clk *clk;
++
++              xclk->isp = isp;
++              xclk->id = i == 0 ? ISP_XCLK_A : ISP_XCLK_B;
++              xclk->divider = 1;
++              spin_lock_init(&xclk->lock);
++
++              init.name = i == 0 ? "cam_xclka" : "cam_xclkb";
++              init.ops = &isp_xclk_ops;
++              init.parent_names = &isp_xclk_parent_name;
++              init.num_parents = 1;
++
++              xclk->hw.init = &init;
++
++              clk = devm_clk_register(isp->dev, &xclk->hw);
++              if (IS_ERR(clk))
++                      return PTR_ERR(clk);
++
++              if (pdata->xclks[i].con_id == NULL &&
++                  pdata->xclks[i].dev_id == NULL)
++                      continue;
++
++              xclk->lookup = kzalloc(sizeof(*xclk->lookup), GFP_KERNEL);
++              if (xclk->lookup == NULL)
++                      return -ENOMEM;
++
++              xclk->lookup->con_id = pdata->xclks[i].con_id;
++              xclk->lookup->dev_id = pdata->xclks[i].dev_id;
++              xclk->lookup->clk = clk;
++
++              clkdev_add(xclk->lookup);
++      }
++
++      return 0;
++}
++
++static void isp_xclk_cleanup(struct isp_device *isp)
++{
++      unsigned int i;
++
++      for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) {
++              struct isp_xclk *xclk = &isp->xclks[i];
++
++              if (xclk->lookup)
++                      clkdev_drop(xclk->lookup);
++      }
++}
++
++/* -----------------------------------------------------------------------------
++ * Interrupts
++ */
++
+ /*
+  * isp_enable_interrupts - Enable ISP interrupts.
+  * @isp: OMAP3 ISP device
+@@ -180,80 +376,6 @@ static void isp_disable_interrupts(struct isp_device *isp)
+       isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+ }
+-/**
+- * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
+- * @isp: OMAP3 ISP device
+- * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high
+- * @xclksel: XCLK to configure (0 = A, 1 = B).
+- *
+- * Configures the specified MCLK divisor in the ISP timing control register
+- * (TCTRL_CTRL) to generate the desired xclk clock value.
+- *
+- * Divisor = cam_mclk_hz / xclk
+- *
+- * Returns the final frequency that is actually being generated
+- **/
+-static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
+-{
+-      u32 divisor;
+-      u32 currentxclk;
+-      unsigned long mclk_hz;
+-
+-      if (!omap3isp_get(isp))
+-              return 0;
+-
+-      mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
+-
+-      if (xclk >= mclk_hz) {
+-              divisor = ISPTCTRL_CTRL_DIV_BYPASS;
+-              currentxclk = mclk_hz;
+-      } else if (xclk >= 2) {
+-              divisor = mclk_hz / xclk;
+-              if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
+-                      divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
+-              currentxclk = mclk_hz / divisor;
+-      } else {
+-              divisor = xclk;
+-              currentxclk = 0;
+-      }
+-
+-      switch (xclksel) {
+-      case ISP_XCLK_A:
+-              isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+-                              ISPTCTRL_CTRL_DIVA_MASK,
+-                              divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
+-              dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
+-                      currentxclk);
+-              break;
+-      case ISP_XCLK_B:
+-              isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+-                              ISPTCTRL_CTRL_DIVB_MASK,
+-                              divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
+-              dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
+-                      currentxclk);
+-              break;
+-      case ISP_XCLK_NONE:
+-      default:
+-              omap3isp_put(isp);
+-              dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
+-                      "xclk. Must be 0 (A) or 1 (B).\n");
+-              return -EINVAL;
+-      }
+-
+-      /* Do we go from stable whatever to clock? */
+-      if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2)
+-              omap3isp_get(isp);
+-      /* Stopping the clock. */
+-      else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2)
+-              omap3isp_put(isp);
+-
+-      isp->xclk_divisor[xclksel - 1] = divisor;
+-
+-      omap3isp_put(isp);
+-
+-      return currentxclk;
+-}
+-
+ /*
+  * isp_core_init - ISP core settings
+  * @isp: OMAP3 ISP device
+@@ -1969,6 +2091,7 @@ static int isp_remove(struct platform_device *pdev)
+       isp_unregister_entities(isp);
+       isp_cleanup_modules(isp);
++      isp_xclk_cleanup(isp);
+       __omap3isp_get(isp, false);
+       iommu_detach_device(isp->domain, &pdev->dev);
+@@ -2042,7 +2165,6 @@ static int isp_probe(struct platform_device *pdev)
+       }
+       isp->autoidle = autoidle;
+-      isp->platform_cb.set_xclk = isp_set_xclk;
+       mutex_init(&isp->isp_mutex);
+       spin_lock_init(&isp->stat_lock);
+@@ -2093,6 +2215,10 @@ static int isp_probe(struct platform_device *pdev)
+       if (ret < 0)
+               goto error_isp;
++      ret = isp_xclk_init(isp);
++      if (ret < 0)
++              goto error_isp;
++
+       /* Memory resources */
+       for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++)
+               if (isp->revision == isp_res_maps[m].isp_rev)
+@@ -2162,6 +2288,7 @@ detach_dev:
+ free_domain:
+       iommu_domain_free(isp->domain);
+ error_isp:
++      isp_xclk_cleanup(isp);
+       omap3isp_put(isp);
+ error:
+       platform_set_drvdata(pdev, NULL);
+diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
+index c77e1f2..cd3eff4 100644
+--- a/drivers/media/platform/omap3isp/isp.h
++++ b/drivers/media/platform/omap3isp/isp.h
+@@ -29,6 +29,7 @@
+ #include <media/omap3isp.h>
+ #include <media/v4l2-device.h>
++#include <linux/clk-provider.h>
+ #include <linux/device.h>
+ #include <linux/io.h>
+ #include <linux/iommu.h>
+@@ -125,8 +126,20 @@ struct isp_reg {
+       u32 val;
+ };
+-struct isp_platform_callback {
+-      u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
++enum isp_xclk_id {
++      ISP_XCLK_A,
++      ISP_XCLK_B,
++};
++
++struct isp_xclk {
++      struct isp_device *isp;
++      struct clk_hw hw;
++      struct clk_lookup *lookup;
++      enum isp_xclk_id id;
++
++      spinlock_t lock;        /* Protects enabled and divider */
++      bool enabled;
++      unsigned int divider;
+ };
+ /*
+@@ -149,6 +162,7 @@ struct isp_platform_callback {
+  * @cam_mclk: Pointer to camera functional clock structure.
+  * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
+  * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
++ * @xclks: External clocks provided by the ISP
+  * @irq: Currently attached ISP ISR callbacks information structure.
+  * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
+  * @isp_hist: Pointer to current settings for ISP Histogram SCM.
+@@ -185,12 +199,12 @@ struct isp_device {
+       int has_context;
+       int ref_count;
+       unsigned int autoidle;
+-      u32 xclk_divisor[2];    /* Two clocks, a and b. */
+ #define ISP_CLK_CAM_ICK               0
+ #define ISP_CLK_CAM_MCLK      1
+ #define ISP_CLK_CSI2_FCK      2
+ #define ISP_CLK_L3_ICK                3
+       struct clk *clock[4];
++      struct isp_xclk xclks[2];
+       /* ISP modules */
+       struct ispstat isp_af;
+@@ -209,8 +223,6 @@ struct isp_device {
+       unsigned int subclk_resources;
+       struct iommu_domain *domain;
+-
+-      struct isp_platform_callback platform_cb;
+ };
+ #define v4l2_dev_to_isp_device(dev) \
+diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
+index 9584269..c9d06d9 100644
+--- a/include/media/omap3isp.h
++++ b/include/media/omap3isp.h
+@@ -29,10 +29,6 @@
+ struct i2c_board_info;
+ struct isp_device;
+-#define ISP_XCLK_NONE                 0
+-#define ISP_XCLK_A                    1
+-#define ISP_XCLK_B                    2
+-
+ enum isp_interface_type {
+       ISP_INTERFACE_PARALLEL,
+       ISP_INTERFACE_CSI2A_PHY2,
+@@ -153,7 +149,13 @@ struct isp_v4l2_subdevs_group {
+       } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
+ };
++struct isp_platform_xclk {
++      const char *dev_id;
++      const char *con_id;
++};
++
+ struct isp_platform_data {
++      struct isp_platform_xclk xclks[2];
+       struct isp_v4l2_subdevs_group *subdevs;
+       void (*set_constraints)(struct isp_device *isp, bool enable);
+ };
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/3isp/0002-mt9m032-Fix-PLL-setup.patch b/src/patches/kernel/omap/3isp/0002-mt9m032-Fix-PLL-setup.patch
new file mode 100644 (file)
index 0000000..9d2b19c
--- /dev/null
@@ -0,0 +1,91 @@
+From 7c44c8a989ad01bd7cd02370d4ca4a742db218be Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 25 Sep 2012 15:46:34 +0200
+Subject: [PATCH 2/6] mt9m032: Fix PLL setup
+
+The MT9M032 PLL was assumed to be identical to the MT9P031 PLL but
+differs significantly. Update the registers definitions and PLL limits
+according to the datasheet.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/i2c/mt9m032.c |   24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
+index f80c1d7e..30d755a 100644
+--- a/drivers/media/i2c/mt9m032.c
++++ b/drivers/media/i2c/mt9m032.c
+@@ -87,7 +87,7 @@
+ #define MT9M032_RESTART                                       0x0b
+ #define MT9M032_RESET                                 0x0d
+ #define MT9M032_PLL_CONFIG1                           0x11
+-#define               MT9M032_PLL_CONFIG1_OUTDIV_MASK         0x3f
++#define               MT9M032_PLL_CONFIG1_PREDIV_MASK         0x3f
+ #define               MT9M032_PLL_CONFIG1_MUL_SHIFT           8
+ #define MT9M032_READ_MODE1                            0x1e
+ #define MT9M032_READ_MODE2                            0x20
+@@ -106,6 +106,8 @@
+ #define               MT9M032_GAIN_AMUL_SHIFT                 6
+ #define               MT9M032_GAIN_ANALOG_MASK                0x3f
+ #define MT9M032_FORMATTER1                            0x9e
++#define               MT9M032_FORMATTER1_PLL_P1_6             (1 << 8)
++#define               MT9M032_FORMATTER1_PARALLEL             (1 << 12)
+ #define MT9M032_FORMATTER2                            0x9f
+ #define               MT9M032_FORMATTER2_DOUT_EN              0x1000
+ #define               MT9M032_FORMATTER2_PIXCLK_EN            0x2000
+@@ -121,8 +123,6 @@
+ #define               MT9P031_PLL_CONTROL_PWROFF              0x0050
+ #define               MT9P031_PLL_CONTROL_PWRON               0x0051
+ #define               MT9P031_PLL_CONTROL_USEPLL              0x0052
+-#define MT9P031_PLL_CONFIG2                           0x11
+-#define               MT9P031_PLL_CONFIG2_P1_DIV_MASK         0x1f
+ struct mt9m032 {
+       struct v4l2_subdev subdev;
+@@ -255,13 +255,14 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
+               .n_max = 64,
+               .m_min = 16,
+               .m_max = 255,
+-              .p1_min = 1,
+-              .p1_max = 128,
++              .p1_min = 6,
++              .p1_max = 7,
+       };
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
+       struct mt9m032_platform_data *pdata = sensor->pdata;
+       struct aptina_pll pll;
++      u16 reg_val;
+       int ret;
+       pll.ext_clock = pdata->ext_clock;
+@@ -274,18 +275,19 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
+       sensor->pix_clock = pdata->pix_clock;
+       ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
+-                          (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT)
+-                          | (pll.p1 - 1));
+-      if (!ret)
+-              ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1);
++                          (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) |
++                          ((pll.n - 1) & MT9M032_PLL_CONFIG1_PREDIV_MASK));
+       if (!ret)
+               ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
+                                   MT9P031_PLL_CONTROL_PWRON |
+                                   MT9P031_PLL_CONTROL_USEPLL);
+       if (!ret)               /* more reserved, Continuous, Master Mode */
+               ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
+-      if (!ret)               /* Set 14-bit mode, select 7 divider */
+-              ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e);
++      if (!ret) {
++              reg_val = (pll.p1 == 6 ? MT9M032_FORMATTER1_PLL_P1_6 : 0)
++                      | MT9M032_FORMATTER1_PARALLEL | 0x001e; /* 14-bit */
++              ret = mt9m032_write(client, MT9M032_FORMATTER1, reg_val);
++      }
+       return ret;
+ }
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/3isp/0003-mt9m032-Define-MT9M032_READ_MODE1-bits.patch b/src/patches/kernel/omap/3isp/0003-mt9m032-Define-MT9M032_READ_MODE1-bits.patch
new file mode 100644 (file)
index 0000000..c80e876
--- /dev/null
@@ -0,0 +1,55 @@
+From 1115becbb4875d62abb10f94a9510c81f376606f Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Wed, 26 Sep 2012 10:54:17 +0200
+Subject: [PATCH 3/6] mt9m032: Define MT9M032_READ_MODE1 bits
+
+Replace hardcoded values with #define's.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/i2c/mt9m032.c |   22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
+index 30d755a..de150d3 100644
+--- a/drivers/media/i2c/mt9m032.c
++++ b/drivers/media/i2c/mt9m032.c
+@@ -90,6 +90,24 @@
+ #define               MT9M032_PLL_CONFIG1_PREDIV_MASK         0x3f
+ #define               MT9M032_PLL_CONFIG1_MUL_SHIFT           8
+ #define MT9M032_READ_MODE1                            0x1e
++#define               MT9M032_READ_MODE1_OUTPUT_BAD_FRAMES    (1 << 13)
++#define               MT9M032_READ_MODE1_MAINTAIN_FRAME_RATE  (1 << 12)
++#define               MT9M032_READ_MODE1_XOR_LINE_VALID       (1 << 11)
++#define               MT9M032_READ_MODE1_CONT_LINE_VALID      (1 << 10)
++#define               MT9M032_READ_MODE1_INVERT_TRIGGER       (1 << 9)
++#define               MT9M032_READ_MODE1_SNAPSHOT             (1 << 8)
++#define               MT9M032_READ_MODE1_GLOBAL_RESET         (1 << 7)
++#define               MT9M032_READ_MODE1_BULB_EXPOSURE        (1 << 6)
++#define               MT9M032_READ_MODE1_INVERT_STROBE        (1 << 5)
++#define               MT9M032_READ_MODE1_STROBE_ENABLE        (1 << 4)
++#define               MT9M032_READ_MODE1_STROBE_START_TRIG1   (0 << 2)
++#define               MT9M032_READ_MODE1_STROBE_START_EXP     (1 << 2)
++#define               MT9M032_READ_MODE1_STROBE_START_SHUTTER (2 << 2)
++#define               MT9M032_READ_MODE1_STROBE_START_TRIG2   (3 << 2)
++#define               MT9M032_READ_MODE1_STROBE_END_TRIG1     (0 << 0)
++#define               MT9M032_READ_MODE1_STROBE_END_EXP       (1 << 0)
++#define               MT9M032_READ_MODE1_STROBE_END_SHUTTER   (2 << 0)
++#define               MT9M032_READ_MODE1_STROBE_END_TRIG2     (3 << 0)
+ #define MT9M032_READ_MODE2                            0x20
+ #define               MT9M032_READ_MODE2_VFLIP_SHIFT          15
+ #define               MT9M032_READ_MODE2_HFLIP_SHIFT          14
+@@ -282,7 +300,9 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
+                                   MT9P031_PLL_CONTROL_PWRON |
+                                   MT9P031_PLL_CONTROL_USEPLL);
+       if (!ret)               /* more reserved, Continuous, Master Mode */
+-              ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
++              ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8000 |
++                                  MT9M032_READ_MODE1_STROBE_START_EXP |
++                                  MT9M032_READ_MODE1_STROBE_END_SHUTTER);
+       if (!ret) {
+               reg_val = (pll.p1 == 6 ? MT9M032_FORMATTER1_PLL_P1_6 : 0)
+                       | MT9M032_FORMATTER1_PARALLEL | 0x001e; /* 14-bit */
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/3isp/0004-mt9p031-Use-devm_-managed-helpers.patch b/src/patches/kernel/omap/3isp/0004-mt9p031-Use-devm_-managed-helpers.patch
new file mode 100644 (file)
index 0000000..bcc4360
--- /dev/null
@@ -0,0 +1,62 @@
+From d3f188f38eaa34acf6375d5d88fe27971aae1170 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Fri, 21 Dec 2012 20:34:06 +0100
+Subject: [PATCH 4/6] mt9p031: Use devm_* managed helpers
+
+Replace kzalloc and gpio_request_one by their managed equivalents.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/i2c/mt9p031.c |   13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
+index e328332..e0bad59 100644
+--- a/drivers/media/i2c/mt9p031.c
++++ b/drivers/media/i2c/mt9p031.c
+@@ -927,7 +927,7 @@ static int mt9p031_probe(struct i2c_client *client,
+               return -EIO;
+       }
+-      mt9p031 = kzalloc(sizeof(*mt9p031), GFP_KERNEL);
++      mt9p031 = devm_kzalloc(&client->dev, sizeof(*mt9p031), GFP_KERNEL);
+       if (mt9p031 == NULL)
+               return -ENOMEM;
+@@ -1001,8 +1001,8 @@ static int mt9p031_probe(struct i2c_client *client,
+       mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
+       if (pdata->reset != -1) {
+-              ret = gpio_request_one(pdata->reset, GPIOF_OUT_INIT_LOW,
+-                                     "mt9p031_rst");
++              ret = devm_gpio_request_one(&client->dev, pdata->reset,
++                                          GPIOF_OUT_INIT_LOW, "mt9p031_rst");
+               if (ret < 0)
+                       goto done;
+@@ -1013,12 +1013,8 @@ static int mt9p031_probe(struct i2c_client *client,
+ done:
+       if (ret < 0) {
+-              if (mt9p031->reset != -1)
+-                      gpio_free(mt9p031->reset);
+-
+               v4l2_ctrl_handler_free(&mt9p031->ctrls);
+               media_entity_cleanup(&mt9p031->subdev.entity);
+-              kfree(mt9p031);
+       }
+       return ret;
+@@ -1032,9 +1028,6 @@ static int mt9p031_remove(struct i2c_client *client)
+       v4l2_ctrl_handler_free(&mt9p031->ctrls);
+       v4l2_device_unregister_subdev(subdev);
+       media_entity_cleanup(&subdev->entity);
+-      if (mt9p031->reset != -1)
+-              gpio_free(mt9p031->reset);
+-      kfree(mt9p031);
+       return 0;
+ }
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/3isp/0005-mt9p031-Add-support-for-regulators.patch b/src/patches/kernel/omap/3isp/0005-mt9p031-Add-support-for-regulators.patch
new file mode 100644 (file)
index 0000000..57c80fd
--- /dev/null
@@ -0,0 +1,82 @@
+From 9ff2bc0c9458f0eecde6d9b52a899fd2bb1dd3a3 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Tue, 8 May 2012 15:10:36 +0200
+Subject: [PATCH 5/6] mt9p031: Add support for regulators
+
+Enable the regulators when powering the sensor up, and disable them when
+powering it down.
+
+The regulators are mandatory. Boards that don't allow controlling the
+sensor power lines must provide fixed voltage regulators.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+---
+ drivers/media/i2c/mt9p031.c |   24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
+index e0bad59..ecf4492 100644
+--- a/drivers/media/i2c/mt9p031.c
++++ b/drivers/media/i2c/mt9p031.c
+@@ -19,6 +19,7 @@
+ #include <linux/i2c.h>
+ #include <linux/log2.h>
+ #include <linux/pm.h>
++#include <linux/regulator/consumer.h>
+ #include <linux/slab.h>
+ #include <linux/videodev2.h>
+@@ -121,6 +122,10 @@ struct mt9p031 {
+       struct mutex power_lock; /* lock to protect power_count */
+       int power_count;
++      struct regulator *vaa;
++      struct regulator *vdd;
++      struct regulator *vdd_io;
++
+       enum mt9p031_model model;
+       struct aptina_pll pll;
+       int reset;
+@@ -264,6 +269,11 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
+               usleep_range(1000, 2000);
+       }
++      /* Bring up the supplies */
++      regulator_enable(mt9p031->vdd);
++      regulator_enable(mt9p031->vdd_io);
++      regulator_enable(mt9p031->vaa);
++
+       /* Emable clock */
+       if (mt9p031->pdata->set_xclk)
+               mt9p031->pdata->set_xclk(&mt9p031->subdev,
+@@ -285,6 +295,10 @@ static void mt9p031_power_off(struct mt9p031 *mt9p031)
+               usleep_range(1000, 2000);
+       }
++      regulator_disable(mt9p031->vaa);
++      regulator_disable(mt9p031->vdd_io);
++      regulator_disable(mt9p031->vdd);
++
+       if (mt9p031->pdata->set_xclk)
+               mt9p031->pdata->set_xclk(&mt9p031->subdev, 0);
+ }
+@@ -937,6 +951,16 @@ static int mt9p031_probe(struct i2c_client *client,
+       mt9p031->model = did->driver_data;
+       mt9p031->reset = -1;
++      mt9p031->vaa = devm_regulator_get(&client->dev, "vaa");
++      mt9p031->vdd = devm_regulator_get(&client->dev, "vdd");
++      mt9p031->vdd_io = devm_regulator_get(&client->dev, "vdd_io");
++
++      if (IS_ERR(mt9p031->vaa) || IS_ERR(mt9p031->vdd) ||
++          IS_ERR(mt9p031->vdd_io)) {
++              dev_err(&client->dev, "Unable to get regulators\n");
++              return -ENODEV;
++      }
++
+       v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6);
+       v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/3isp/0006-mt9p031-Use-the-common-clock-framework.patch b/src/patches/kernel/omap/3isp/0006-mt9p031-Use-the-common-clock-framework.patch
new file mode 100644 (file)
index 0000000..fc8d583
--- /dev/null
@@ -0,0 +1,110 @@
+From 6cd62f5ae305142c0490e80caa04f99f00029b68 Mon Sep 17 00:00:00 2001
+From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Date: Fri, 21 Dec 2012 20:11:55 +0100
+Subject: [PATCH 6/6] mt9p031: Use the common clock framework
+
+Configure the device external clock using the common clock framework
+instead of a board code callback function.
+
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Acked-by: Sakari Ailus <sakari.ailus@iki.fi>
+---
+ drivers/media/i2c/mt9p031.c |   21 ++++++++++++++-------
+ include/media/mt9p031.h     |    2 --
+ 2 files changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
+index ecf4492..28cf95b 100644
+--- a/drivers/media/i2c/mt9p031.c
++++ b/drivers/media/i2c/mt9p031.c
+@@ -12,6 +12,7 @@
+  * published by the Free Software Foundation.
+  */
++#include <linux/clk.h>
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/gpio.h>
+@@ -122,6 +123,7 @@ struct mt9p031 {
+       struct mutex power_lock; /* lock to protect power_count */
+       int power_count;
++      struct clk *clk;
+       struct regulator *vaa;
+       struct regulator *vdd;
+       struct regulator *vdd_io;
+@@ -200,7 +202,7 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
+                                         0);
+ }
+-static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
++static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
+ {
+       static const struct aptina_pll_limits limits = {
+               .ext_clock_min = 6000000,
+@@ -221,6 +223,12 @@ static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+       struct mt9p031_platform_data *pdata = mt9p031->pdata;
++      mt9p031->clk = devm_clk_get(&client->dev, NULL);
++      if (IS_ERR(mt9p031->clk))
++              return PTR_ERR(mt9p031->clk);
++
++      clk_set_rate(mt9p031->clk, pdata->ext_freq);
++
+       mt9p031->pll.ext_clock = pdata->ext_freq;
+       mt9p031->pll.pix_clock = pdata->target_freq;
+@@ -275,9 +283,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
+       regulator_enable(mt9p031->vaa);
+       /* Emable clock */
+-      if (mt9p031->pdata->set_xclk)
+-              mt9p031->pdata->set_xclk(&mt9p031->subdev,
+-                                       mt9p031->pdata->ext_freq);
++      if (mt9p031->clk)
++              clk_prepare_enable(mt9p031->clk);
+       /* Now RESET_BAR must be high */
+       if (mt9p031->reset != -1) {
+@@ -299,8 +306,8 @@ static void mt9p031_power_off(struct mt9p031 *mt9p031)
+       regulator_disable(mt9p031->vdd_io);
+       regulator_disable(mt9p031->vdd);
+-      if (mt9p031->pdata->set_xclk)
+-              mt9p031->pdata->set_xclk(&mt9p031->subdev, 0);
++      if (mt9p031->clk)
++              clk_disable_unprepare(mt9p031->clk);
+ }
+ static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on)
+@@ -1033,7 +1040,7 @@ static int mt9p031_probe(struct i2c_client *client,
+               mt9p031->reset = pdata->reset;
+       }
+-      ret = mt9p031_pll_setup(mt9p031);
++      ret = mt9p031_clk_setup(mt9p031);
+ done:
+       if (ret < 0) {
+diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
+index 0c97b19..b1e63f2 100644
+--- a/include/media/mt9p031.h
++++ b/include/media/mt9p031.h
+@@ -5,13 +5,11 @@ struct v4l2_subdev;
+ /*
+  * struct mt9p031_platform_data - MT9P031 platform data
+- * @set_xclk: Clock frequency set callback
+  * @reset: Chip reset GPIO (set to -1 if not used)
+  * @ext_freq: Input clock frequency
+  * @target_freq: Pixel clock frequency
+  */
+ struct mt9p031_platform_data {
+-      int (*set_xclk)(struct v4l2_subdev *subdev, int hz);
+       int reset;
+       int ext_freq;
+       int target_freq;
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/0001-meego-modedb-add-Toshiba-LTA070B220F-800x480-support.patch b/src/patches/kernel/omap/beagle/0001-meego-modedb-add-Toshiba-LTA070B220F-800x480-support.patch
new file mode 100644 (file)
index 0000000..34d6034
--- /dev/null
@@ -0,0 +1,30 @@
+From 6ac98647956cbff190954b4cac6bd71fdbb8647b Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Wed, 23 Mar 2011 08:37:54 -0500
+Subject: [PATCH 1/5] meego: modedb add Toshiba LTA070B220F 800x480 support
+
+ from http://wiki.meego.com/ARM/Meego_on_Beagleboard_from_scratch
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/video/modedb.c |    4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
+index 5b686de..69ad1ec 100644
+--- a/drivers/video/modedb.c
++++ b/drivers/video/modedb.c
+@@ -293,6 +293,10 @@ static const struct fb_videomode modedb[] = {
+       /* 864x480 @ 60 Hz, 35.15 kHz hsync */
+       { NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0,
+               0, FB_VMODE_NONINTERLACED },
++
++      /* 800x480 @ 60 Hz, Toshiba LTA070B220F 7 inch LCD */
++      {  NULL, 60, 800, 480, 32787, 48, 80, 33, 31, 32, 2,
++              FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED },
+ };
+ #ifdef CONFIG_FB_MODE_HELPERS
+-- 
+1.7.7.6
+
diff --git a/src/patches/kernel/omap/beagle/0002-backlight-Add-TLC59108-backlight-control-driver.patch b/src/patches/kernel/omap/beagle/0002-backlight-Add-TLC59108-backlight-control-driver.patch
new file mode 100644 (file)
index 0000000..ce4df82
--- /dev/null
@@ -0,0 +1,217 @@
+From e989473bea15beef8d480b822a619e7b8fca860c Mon Sep 17 00:00:00 2001
+From: "Manjunathappa, Prakash" <prakash.pm@ti.com>
+Date: Mon, 1 Aug 2011 18:25:11 +0530
+Subject: [PATCH 2/5] backlight: Add TLC59108 backlight control driver
+
+This patch adds support for I2C configurable TLC59108 backlight
+control driver.
+
+Signed-off-by: Manjunathappa, Prakash <prakash.pm@ti.com>
+Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
+---
+ drivers/video/backlight/Kconfig    |    8 ++
+ drivers/video/backlight/Makefile   |    1 +
+ drivers/video/backlight/tlc59108.c |  160 ++++++++++++++++++++++++++++++++++++
+ 3 files changed, 169 insertions(+)
+ create mode 100644 drivers/video/backlight/tlc59108.c
+
+diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
+index db10d01..04a2275 100644
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -418,6 +418,14 @@ config BACKLIGHT_AS3711
+         If you have an Austrian Microsystems AS3711 say Y to enable the
+         backlight driver.
++config BACKLIGHT_TLC59108
++      tristate "TLC59108 LCD Backlight Driver"
++      depends on I2C && BACKLIGHT_CLASS_DEVICE
++      default n
++      help
++        If you have an LCD Panel with backlight control via TLC59108,
++        say Y to enable its LCD control driver.
++
+ endif # BACKLIGHT_CLASS_DEVICE
+ endif # BACKLIGHT_LCD_SUPPORT
+diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
+index 96c4d62..3687852 100644
+--- a/drivers/video/backlight/Makefile
++++ b/drivers/video/backlight/Makefile
+@@ -41,6 +41,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X)               += lp855x_bl.o
+ obj-$(CONFIG_BACKLIGHT_LP8788)                += lp8788_bl.o
+ obj-$(CONFIG_BACKLIGHT_MAX8925)               += max8925_bl.o
+ obj-$(CONFIG_BACKLIGHT_OMAP1)         += omap1_bl.o
++obj-$(CONFIG_BACKLIGHT_TLC59108)      += tlc59108.o
+ obj-$(CONFIG_BACKLIGHT_OT200)         += ot200_bl.o
+ obj-$(CONFIG_BACKLIGHT_PANDORA)               += pandora_bl.o
+ obj-$(CONFIG_BACKLIGHT_PCF50633)      += pcf50633-backlight.o
+diff --git a/drivers/video/backlight/tlc59108.c b/drivers/video/backlight/tlc59108.c
+new file mode 100644
+index 0000000..4f4ea34
+--- /dev/null
++++ b/drivers/video/backlight/tlc59108.c
+@@ -0,0 +1,160 @@
++/*
++ * ti81xxhdmi_tlc59108.c
++ *
++ * Copyright (C) 2011 Texas Instruments
++ * Author: Senthil Natarajan
++ *
++ * tlc59108 HDMI Driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ *
++ * 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/>.
++ * History:
++ *
++ * Senthil Natarajan<senthil.n@ti.com> July 2011 I2C driver for tlc59108
++ *                                             backlight control
++ */
++
++#include <linux/i2c.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/backlight.h>
++#include <linux/fb.h>
++
++#define tlc59108_MODULE_NAME  "tlc59108"
++#define TLC59108_MODE1   0x00
++#define TLC59108_PWM2    0x04
++#define TLC59108_LEDOUT0 0x0c
++#define TLC59108_LEDOUT1 0x0d
++#define TLC59108_MAX_BRIGHTNESS 0xFF
++
++struct tlc59108_bl {
++      struct i2c_client *client;
++      struct backlight_device *bl;
++};
++
++static void tlc59108_bl_set_backlight(struct tlc59108_bl *data, int brightness)
++{
++      /* Set Mode1 Register */
++      i2c_smbus_write_byte_data(data->client, TLC59108_MODE1, 0x00);
++
++      /* Set LEDOUT0 Register */
++      i2c_smbus_write_byte_data(data->client, TLC59108_LEDOUT0, 0x21);
++
++      /* Set Backlight Duty Cycle*/
++      i2c_smbus_write_byte_data(data->client, TLC59108_PWM2,
++                                brightness & 0xff);
++}
++
++static int tlc59108_bl_get_brightness(struct backlight_device *dev)
++{
++      struct backlight_properties *props = &dev->props;
++
++      return props->brightness;
++}
++
++static int tlc59108_bl_update_status(struct backlight_device *dev)
++{
++      struct backlight_properties *props = &dev->props;
++      struct tlc59108_bl *data = dev_get_drvdata(&dev->dev);
++      int brightness = props->brightness;
++
++      tlc59108_bl_set_backlight(data, brightness);
++
++      return 0;
++}
++
++static const struct backlight_ops bl_ops = {
++      .get_brightness         = tlc59108_bl_get_brightness,
++      .update_status          = tlc59108_bl_update_status,
++};
++
++static int tlc59108_probe(struct i2c_client *c, const struct i2c_device_id *id)
++{
++      struct backlight_properties props;
++      struct tlc59108_bl *data = kzalloc(sizeof(struct tlc59108_bl),
++                                         GFP_KERNEL);
++      int ret = 0;
++
++      if (!data)
++              return -ENOMEM;
++
++      i2c_set_clientdata(c, data);
++      data->client = c;
++
++      memset(&props, 0, sizeof(struct backlight_properties));
++      props.max_brightness = TLC59108_MAX_BRIGHTNESS;
++      props.type = BACKLIGHT_RAW;
++      data->bl = backlight_device_register("tlc59108-bl", &c->dev, data,
++                                           &bl_ops, &props);
++      if (IS_ERR(data->bl)) {
++              ret = PTR_ERR(data->bl);
++              goto err_reg;
++      }
++
++      data->bl->props.brightness = TLC59108_MAX_BRIGHTNESS;
++
++      backlight_update_status(data->bl);
++
++      return 0;
++
++err_reg:
++      data->bl = NULL;
++      kfree(data);
++      return ret;
++}
++
++static int tlc59108_remove(struct i2c_client *c)
++{
++      struct tlc59108_bl *data = i2c_get_clientdata(c);
++
++      backlight_device_unregister(data->bl);
++      data->bl = NULL;
++
++      kfree(data);
++
++      return 0;
++}
++
++/* I2C Device ID table */
++static const struct i2c_device_id tlc59108_id[] = {
++      { "tlc59108", 0 },
++      { }
++};
++MODULE_DEVICE_TABLE(i2c, tlc59108_id);
++
++/* I2C driver data */
++static struct i2c_driver tlc59108_driver = {
++      .driver = {
++              .owner = THIS_MODULE,
++              .name = tlc59108_MODULE_NAME,
++      },
++      .probe = tlc59108_probe,
++      .remove = tlc59108_remove,
++      .id_table = tlc59108_id,
++};
++
++static int __init tlc59108_init(void)
++{
++      return i2c_add_driver(&tlc59108_driver);
++}
++
++static void __exit tlc59108_exit(void)
++{
++      i2c_del_driver(&tlc59108_driver);
++}
++
++module_init(tlc59108_init);
++module_exit(tlc59108_exit);
++
++MODULE_DESCRIPTION("LCD/Backlight control for TLC59108");
++MODULE_AUTHOR("Senthil Natarajan <senthil.n@ti.com>");
++MODULE_LICENSE("GPL v2");
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/0003-tlc59108-adjust-for-beagleboard-uLCD7.patch b/src/patches/kernel/omap/beagle/0003-tlc59108-adjust-for-beagleboard-uLCD7.patch
new file mode 100644 (file)
index 0000000..5c9659b
--- /dev/null
@@ -0,0 +1,124 @@
+From 40cbddde06a9f0e1845810b904502f922fc3288f Mon Sep 17 00:00:00 2001
+From: Koen Kooi <koen@dominion.thruhere.net>
+Date: Fri, 27 Apr 2012 21:30:00 +0200
+Subject: [PATCH 3/5] tlc59108: adjust for beagleboard+uLCD7
+
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+---
+ drivers/video/backlight/tlc59108.c |   46 ++++++++++++++++++++++++-----------
+ 1 files changed, 31 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/video/backlight/tlc59108.c b/drivers/video/backlight/tlc59108.c
+index 4f4ea34..40a21e7 100644
+--- a/drivers/video/backlight/tlc59108.c
++++ b/drivers/video/backlight/tlc59108.c
+@@ -29,9 +29,16 @@
+ #include <linux/backlight.h>
+ #include <linux/fb.h>
+-#define tlc59108_MODULE_NAME  "tlc59108"
+ #define TLC59108_MODE1   0x00
+-#define TLC59108_PWM2    0x04
++#define TLC59108_MODE2   0x01
++#define TLC59108_PWM0 0x02
++#define TLC59108_PWM1 0x03
++#define TLC59108_PWM2 0x04
++#define TLC59108_PWM3 0x05
++#define TLC59108_PWM4 0x06
++#define TLC59108_PWM5 0x07
++#define TLC59108_PWM6 0x08
++#define TLC59108_PWM7 0x09
+ #define TLC59108_LEDOUT0 0x0c
+ #define TLC59108_LEDOUT1 0x0d
+ #define TLC59108_MAX_BRIGHTNESS 0xFF
+@@ -43,15 +50,9 @@ struct tlc59108_bl {
+ static void tlc59108_bl_set_backlight(struct tlc59108_bl *data, int brightness)
+ {
+-      /* Set Mode1 Register */
+-      i2c_smbus_write_byte_data(data->client, TLC59108_MODE1, 0x00);
+-
+-      /* Set LEDOUT0 Register */
+-      i2c_smbus_write_byte_data(data->client, TLC59108_LEDOUT0, 0x21);
+-
+       /* Set Backlight Duty Cycle*/
+       i2c_smbus_write_byte_data(data->client, TLC59108_PWM2,
+-                                brightness & 0xff);
++                                0xff - brightness );
+ }
+ static int tlc59108_bl_get_brightness(struct backlight_device *dev)
+@@ -65,8 +66,18 @@ static int tlc59108_bl_update_status(struct backlight_device *dev)
+ {
+       struct backlight_properties *props = &dev->props;
+       struct tlc59108_bl *data = dev_get_drvdata(&dev->dev);
++
+       int brightness = props->brightness;
++      if (dev->props.state & BL_CORE_FBBLANK) {
++              brightness = 0;
++              /* Set LEDOUT0 Register */
++              i2c_smbus_write_byte_data(data->client, TLC59108_LEDOUT0, 0x10);
++      } else {
++              /* Set LEDOUT0 Register */
++              i2c_smbus_write_byte_data(data->client, TLC59108_LEDOUT0, 0x30);
++      }
++
+       tlc59108_bl_set_backlight(data, brightness);
+       return 0;
+@@ -77,7 +88,7 @@ static const struct backlight_ops bl_ops = {
+       .update_status          = tlc59108_bl_update_status,
+ };
+-static int tlc59108_probe(struct i2c_client *c, const struct i2c_device_id *id)
++static int __devinit tlc59108_probe(struct i2c_client *c, const struct i2c_device_id *id)
+ {
+       struct backlight_properties props;
+       struct tlc59108_bl *data = kzalloc(sizeof(struct tlc59108_bl),
+@@ -104,6 +115,11 @@ static int tlc59108_probe(struct i2c_client *c, const struct i2c_device_id *id)
+       backlight_update_status(data->bl);
++      i2c_smbus_write_byte_data(data->client, TLC59108_MODE1, 0x00);
++      i2c_smbus_write_byte_data(data->client, TLC59108_PWM2, 0x80);
++      i2c_smbus_write_byte_data(data->client, TLC59108_LEDOUT1, 0x05);
++      i2c_smbus_write_byte_data(data->client, TLC59108_LEDOUT1, 0x15);
++
+       return 0;
+ err_reg:
+@@ -125,7 +141,7 @@ static int tlc59108_remove(struct i2c_client *c)
+ }
+ /* I2C Device ID table */
+-static const struct i2c_device_id tlc59108_id[] = {
++static struct i2c_device_id tlc59108_id[] = {
+       { "tlc59108", 0 },
+       { }
+ };
+@@ -134,12 +150,12 @@ MODULE_DEVICE_TABLE(i2c, tlc59108_id);
+ /* I2C driver data */
+ static struct i2c_driver tlc59108_driver = {
+       .driver = {
+-              .owner = THIS_MODULE,
+-              .name = tlc59108_MODULE_NAME,
++              .owner  = THIS_MODULE,
++              .name   = "tlc59108"
+       },
++      .id_table = tlc59108_id,
+       .probe = tlc59108_probe,
+       .remove = tlc59108_remove,
+-      .id_table = tlc59108_id,
+ };
+ static int __init tlc59108_init(void)
+@@ -157,4 +173,4 @@ module_exit(tlc59108_exit);
+ MODULE_DESCRIPTION("LCD/Backlight control for TLC59108");
+ MODULE_AUTHOR("Senthil Natarajan <senthil.n@ti.com>");
+-MODULE_LICENSE("GPL v2");
++MODULE_LICENSE("GPL");
+-- 
+1.7.7.6
+
diff --git a/src/patches/kernel/omap/beagle/0004-zeroMAP-Open-your-eyes.patch b/src/patches/kernel/omap/beagle/0004-zeroMAP-Open-your-eyes.patch
new file mode 100644 (file)
index 0000000..d179420
--- /dev/null
@@ -0,0 +1,31 @@
+From 81ff7627ad0d958a5c156cb7d880af8707e14f47 Mon Sep 17 00:00:00 2001
+From: Alexander Holler <holler@ahsoftware.de>
+Date: Wed, 4 Jul 2012 00:03:04 +0200
+Subject: [PATCH 4/5] zeroMAP: Open your eyes!
+
+Signed-off-by: Alexander Holler <holler@ahsoftware.de>
+---
+ kernel/printk.c |    7 +++++++
+ 1 files changed, 7 insertions(+), 0 deletions(-)
+
+diff --git a/kernel/printk.c b/kernel/printk.c
+index 22e070f..3678740 100644
+--- a/kernel/printk.c
++++ b/kernel/printk.c
+@@ -1759,6 +1759,13 @@ static int __init console_setup(char *str)
+       char *s, *options, *brl_options = NULL;
+       int idx;
++#ifdef CONFIG_SERIAL_OMAP
++      if (!strncmp(str, "tty0", 4) && '0' <= str[4] && '9' >= str[4]) {
++              str[3] = 'O';
++              pr_warn("We are opening your eyes, assuming you want to use an OMAP based serial driver and not a zeroMAP based one! ;)\n");
++              pr_warn("Which means 'tty0%s' was changed to 'ttyO%s' automagically for your pleasure.\n", str+4, str+4);
++      }
++#endif
+ #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+       if (!memcmp(str, "brl,", 4)) {
+               brl_options = "";
+-- 
+1.7.7.6
+
diff --git a/src/patches/kernel/omap/beagle/0005-ARM-OMAP-Beagle-use-TWL4030-generic-reset-script.patch b/src/patches/kernel/omap/beagle/0005-ARM-OMAP-Beagle-use-TWL4030-generic-reset-script.patch
new file mode 100644 (file)
index 0000000..ffb5ffb
--- /dev/null
@@ -0,0 +1,29 @@
+From f2ec859cb99e6137d78b457f8a6693e69e3b1f33 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Thu, 24 Jan 2013 09:43:51 -0600
+Subject: [PATCH 5/5] ARM: OMAP: Beagle: use TWL4030 generic reset script
+
+Enable TWL_COMMON_PDATA_POWER such that OMAP3530 revisions of the
+Beagle (Bx/Cx) will not hang on reboot when running at 125 Mhz.
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 5b57885..9a2c80b 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -831,7 +831,7 @@ static int __init omap3_beagle_i2c_init(void)
+ {
+       omap3_pmic_get_config(&beagle_twldata,
+                       TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC |
+-                      TWL_COMMON_PDATA_AUDIO,
++                      TWL_COMMON_PDATA_AUDIO | TWL_COMMON_PDATA_POWER,
+                       TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2);
+       beagle_twldata.vpll2->constraints.name = "VDVI";
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/0006-DSS2-use-DSI-PLL-for-DPI-with-OMAP3.patch b/src/patches/kernel/omap/beagle/0006-DSS2-use-DSI-PLL-for-DPI-with-OMAP3.patch
new file mode 100644 (file)
index 0000000..56879cb
--- /dev/null
@@ -0,0 +1,28 @@
+From 40d889a09a05765138f3b737becadfe927c9b004 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 19 Mar 2013 13:40:50 -0500
+Subject: [PATCH 6/6] DSS2: use DSI PLL for DPI with OMAP3
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/video/omap2/dss/dpi.c |    4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
+index 757b57f..12ed14f 100644
+--- a/drivers/video/omap2/dss/dpi.c
++++ b/drivers/video/omap2/dss/dpi.c
+@@ -58,10 +58,6 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
+        */
+       switch (omapdss_get_version()) {
+       case OMAPDSS_VER_OMAP24xx:
+-      case OMAPDSS_VER_OMAP34xx_ES1:
+-      case OMAPDSS_VER_OMAP34xx_ES3:
+-      case OMAPDSS_VER_OMAP3630:
+-      case OMAPDSS_VER_AM35xx:
+               return NULL;
+       case OMAPDSS_VER_OMAP4430_ES1:
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0001-Beagle-expansion-add-buddy-param-for-expansionboard-.patch b/src/patches/kernel/omap/beagle/expansion/0001-Beagle-expansion-add-buddy-param-for-expansionboard-.patch
new file mode 100644 (file)
index 0000000..44a1ae3
--- /dev/null
@@ -0,0 +1,63 @@
+From c070885eaf883884f89a77e2f71def5b447f914b Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 11 Dec 2012 06:25:27 -0600
+Subject: [PATCH 01/10] Beagle: expansion: add buddy param for expansionboard
+ names
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index c3558f9..29d549c 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -23,6 +23,7 @@
+ #include <linux/pwm.h>
+ #include <linux/leds_pwm.h>
+ #include <linux/gpio.h>
++#include <linux/irq.h>
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
+ #include <linux/opp.h>
+@@ -191,6 +192,8 @@ static void __init omap3_beagle_init_rev(void)
+       }
+ }
++char expansionboard_name[16];
++
+ static struct mtd_partition omap3beagle_nand_partitions[] = {
+       /* All the partition sizes are listed in terms of NAND block size */
+       {
+@@ -470,6 +473,18 @@ static struct omap_board_mux board_mux[] __initdata = {
+ };
+ #endif
++static int __init expansionboard_setup(char *str)
++{
++      if (!machine_is_omap3_beagle())
++              return 0;
++
++      if (!str)
++              return -EINVAL;
++      strncpy(expansionboard_name, str, 16);
++      pr_info("Beagle expansionboard: %s\n", expansionboard_name);
++      return 0;
++}
++
+ static int __init beagle_opp_init(void)
+ {
+       int r = 0;
+@@ -559,6 +574,8 @@ static void __init omap3_beagle_init(void)
+       pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup));
+ }
++early_param("buddy", expansionboard_setup);
++
+ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+       /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+       .atag_offset    = 0x100,
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0002-Beagle-expansion-add-zippy.patch b/src/patches/kernel/omap/beagle/expansion/0002-Beagle-expansion-add-zippy.patch
new file mode 100644 (file)
index 0000000..fff6243
--- /dev/null
@@ -0,0 +1,242 @@
+From e71075202707e044a28604bd929fd6f7a89adeae Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Mon, 21 Jan 2013 11:47:02 -0600
+Subject: [PATCH 02/10] Beagle: expansion: add zippy
+
+v2: add #include <linux/regulator/fixed.h>
+build fix from Pantelis Antoniou <panto@antoniou-consulting.com>
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |  164 +++++++++++++++++++++++++++++--
+ 1 file changed, 158 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 4e6e767..b3685ed 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -37,6 +37,7 @@
+ #include <linux/usb/nop-usb-xceiv.h>
+ #include <linux/regulator/machine.h>
++#include <linux/regulator/fixed.h>
+ #include <linux/i2c/twl.h>
+ #include <asm/mach-types.h>
+@@ -195,6 +196,86 @@ static void __init omap3_beagle_init_rev(void)
+ char expansionboard_name[16];
++enum {
++      EXPANSION_MMC_NONE = 0,
++      EXPANSION_MMC_ZIPPY,
++      EXPANSION_MMC_WIFI,
++};
++
++enum {
++      EXPANSION_I2C_NONE = 0,
++      EXPANSION_I2C_ZIPPY,
++};
++
++static struct {
++      int mmc_settings;
++      int i2c_settings;
++} expansion_config = {
++      .mmc_settings = EXPANSION_MMC_NONE,
++      .i2c_settings = EXPANSION_I2C_NONE,
++};
++
++//rcn-ee: this is just a fake regulator, the zippy hardware provides 3.3/1.8 with jumper..
++static struct fixed_voltage_config beagle_vzippy = {
++      .supply_name = "vzippy",
++      .microvolts = 3300000,  /* 3.3V */
++      .startup_delay = 70000, /* 70ms */
++      .enable_high = 1,
++      .enabled_at_boot = 0,
++      .init_data = &beagle_vmmc2,
++};
++
++static struct platform_device omap_zippy_device = {
++      .name   = "reg-fixed-voltage",
++      .id             = 1,
++      .dev = {
++              .platform_data = &beagle_vzippy,
++      },
++};
++
++#define OMAP3BEAGLE_GPIO_ZIPPY_MMC_WP 141
++#define OMAP3BEAGLE_GPIO_ZIPPY_MMC_CD 162
++
++#if IS_ENABLED(CONFIG_ENC28J60)
++#include <linux/platform_data/spi-omap2-mcspi.h>
++#include <linux/spi/spi.h>
++
++#define OMAP3BEAGLE_GPIO_ENC28J60_IRQ 157
++
++static struct omap2_mcspi_device_config enc28j60_spi_chip_info = {
++      .turbo_mode     = 0,
++};
++
++static struct spi_board_info omap3beagle_zippy_spi_board_info[] __initdata = {
++      {
++              .modalias               = "enc28j60",
++              .bus_num                = 4,
++              .chip_select    = 0,
++              .max_speed_hz   = 20000000,
++              .controller_data        = &enc28j60_spi_chip_info,
++      },
++};
++
++static void __init omap3beagle_enc28j60_init(void)
++{
++      if ((gpio_request(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, "ENC28J60_IRQ") == 0) &&
++          (gpio_direction_input(OMAP3BEAGLE_GPIO_ENC28J60_IRQ) == 0)) {
++              gpio_export(OMAP3BEAGLE_GPIO_ENC28J60_IRQ, 0);
++              omap3beagle_zippy_spi_board_info[0].irq = gpio_to_irq(OMAP3BEAGLE_GPIO_ENC28J60_IRQ);
++              irq_set_irq_type(omap3beagle_zippy_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
++      } else {
++              pr_err("Beagle expansionboard: could not obtain gpio for ENC28J60_IRQ\n");
++              return;
++      }
++
++      spi_register_board_info(omap3beagle_zippy_spi_board_info,
++                      ARRAY_SIZE(omap3beagle_zippy_spi_board_info));
++}
++
++#else
++static inline void __init omap3beagle_enc28j60_init(void) { return; }
++#endif
++
+ static struct mtd_partition omap3beagle_nand_partitions[] = {
+       /* All the partition sizes are listed in terms of NAND block size */
+       {
+@@ -271,6 +352,23 @@ static struct omap2_hsmmc_info mmc[] = {
+       {}      /* Terminator */
+ };
++static struct omap2_hsmmc_info mmc_zippy[] = {
++      {
++              .mmc            = 1,
++              .caps           = MMC_CAP_4_BIT_DATA,
++              .gpio_wp        = -EINVAL,
++              .deferred       = true,
++      },
++      {
++              .mmc            = 2,
++              .caps           = MMC_CAP_4_BIT_DATA,
++              .gpio_wp        = OMAP3BEAGLE_GPIO_ZIPPY_MMC_WP,
++              .gpio_cd        = OMAP3BEAGLE_GPIO_ZIPPY_MMC_CD,
++              .transceiver    = true,
++              .deferred       = true,
++      },
++      {}      /* Terminator */
++};
+ static struct regulator_consumer_supply beagle_vmmc1_supply[] = {
+       REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
+ };
+@@ -301,10 +399,21 @@ static int beagle_twl_gpio_setup(struct device *dev,
+ {
+       int r;
+-      mmc[0].gpio_wp = beagle_config.mmc1_gpio_wp;
+-      /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+-      mmc[0].gpio_cd = gpio + 0;
+-      omap_hsmmc_late_init(mmc);
++      switch (expansion_config.mmc_settings) {
++      case EXPANSION_MMC_ZIPPY:
++              mmc_zippy[0].gpio_wp = beagle_config.mmc1_gpio_wp;
++              /* gpio + 0 is "mmc0_cd" (input/IRQ) */
++              mmc_zippy[0].gpio_cd = gpio + 0;
++
++              omap_hsmmc_late_init(mmc_zippy);
++              break;
++      default:
++              mmc[0].gpio_wp = beagle_config.mmc1_gpio_wp;
++              /* gpio + 0 is "mmc0_cd" (input/IRQ) */
++              mmc[0].gpio_cd = gpio + 0;
++
++              omap_hsmmc_late_init(mmc);
++      }
+       /*
+        * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
+@@ -396,6 +505,14 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+        },
+ };
++static struct i2c_board_info __initdata zippy_i2c2_rtc[] = {
++#if defined(CONFIG_RTC_DRV_DS1307) || defined(CONFIG_RTC_DRV_DS1307_MODULE)
++      {
++              I2C_BOARD_INFO("ds1307", 0x68),
++      },
++#endif
++};
++
+ static int __init omap3_beagle_i2c_init(void)
+ {
+       omap3_pmic_get_config(&beagle_twldata,
+@@ -406,6 +523,15 @@ static int __init omap3_beagle_i2c_init(void)
+       beagle_twldata.vpll2->constraints.name = "VDVI";
+       omap3_pmic_init("twl4030", &beagle_twldata);
++
++      switch (expansion_config.i2c_settings) {
++      case EXPANSION_I2C_ZIPPY:
++              omap_register_i2c_bus(2, 400, zippy_i2c2_rtc, ARRAY_SIZE(zippy_i2c2_rtc));
++              break;
++      default:
++              omap_register_i2c_bus(2, 400, NULL, 0);
++      }
++
+       /* Bus 3 is attached to the DVI port where devices like the pico DLP
+        * projector don't work reliably with 400kHz */
+       omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
+@@ -548,10 +674,30 @@ static void __init omap3_beagle_init(void)
+       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap3_beagle_init_rev();
++      if (!strcmp(expansionboard_name, "zippy"))
++      {
++              pr_info("Beagle expansionboard: initializing zippy mmc\n");
++              platform_device_register(&omap_zippy_device);
++
++              expansion_config.i2c_settings = EXPANSION_I2C_ZIPPY;
++              expansion_config.mmc_settings = EXPANSION_MMC_ZIPPY;
++
++              omap_mux_init_gpio(OMAP3BEAGLE_GPIO_ZIPPY_MMC_WP, OMAP_PIN_INPUT);
++              omap_mux_init_gpio(OMAP3BEAGLE_GPIO_ZIPPY_MMC_CD, OMAP_PIN_INPUT);
++      }
++
+       if (gpio_is_valid(beagle_config.mmc1_gpio_wp))
+               omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
+-      mmc[0].caps = beagle_config.mmc_caps;
+-      omap_hsmmc_init(mmc);
++
++      switch (expansion_config.mmc_settings) {
++      case EXPANSION_MMC_ZIPPY:
++              mmc_zippy[0].caps = beagle_config.mmc_caps;
++              omap_hsmmc_init(mmc_zippy);
++              break;
++      default:
++              mmc[0].caps = beagle_config.mmc_caps;
++              omap_hsmmc_init(mmc);
++      }
+       omap3_beagle_i2c_init();
+@@ -566,6 +712,12 @@ static void __init omap3_beagle_init(void)
+       omap_sdrc_init(mt46h32m32lf6_sdrc_params,
+                                 mt46h32m32lf6_sdrc_params);
++      if (!strcmp(expansionboard_name, "zippy"))
++      {
++              pr_info("Beagle expansionboard: initializing enc28j60\n");
++              omap3beagle_enc28j60_init();
++      }
++
+       usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+       usb_musb_init(NULL);
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0003-Beagle-expansion-add-zippy2.patch b/src/patches/kernel/omap/beagle/expansion/0003-Beagle-expansion-add-zippy2.patch
new file mode 100644 (file)
index 0000000..b569f92
--- /dev/null
@@ -0,0 +1,86 @@
+From 45bed17e65e1a83f753896e250f3458654dcb229 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 11 Dec 2012 06:32:15 -0600
+Subject: [PATCH 03/10] Beagle: expansion: add zippy2
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   48 ++++++++++++++++++++++++++++++-
+ 1 file changed, 47 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index b3685ed..74da505 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -276,6 +276,46 @@ static void __init omap3beagle_enc28j60_init(void)
+ static inline void __init omap3beagle_enc28j60_init(void) { return; }
+ #endif
++#if IS_ENABLED(CONFIG_KS8851)
++#include <linux/platform_data/spi-omap2-mcspi.h>
++#include <linux/spi/spi.h>
++
++#define OMAP3BEAGLE_GPIO_KS8851_IRQ 157
++
++static struct omap2_mcspi_device_config ks8851_spi_chip_info = {
++      .turbo_mode     = 0,
++};
++
++static struct spi_board_info omap3beagle_zippy2_spi_board_info[] __initdata = {
++      {
++              .modalias               = "ks8851",
++              .bus_num                = 4,
++              .chip_select    = 0,
++              .max_speed_hz   = 36000000,
++              .controller_data        = &ks8851_spi_chip_info,
++      },
++};
++
++static void __init omap3beagle_ks8851_init(void)
++{
++      if ((gpio_request(OMAP3BEAGLE_GPIO_KS8851_IRQ, "KS8851_IRQ") == 0) &&
++          (gpio_direction_input(OMAP3BEAGLE_GPIO_KS8851_IRQ) == 0)) {
++              gpio_export(OMAP3BEAGLE_GPIO_KS8851_IRQ, 0);
++              omap3beagle_zippy2_spi_board_info[0].irq = gpio_to_irq(OMAP3BEAGLE_GPIO_KS8851_IRQ);
++              irq_set_irq_type(omap3beagle_zippy2_spi_board_info[0].irq, IRQ_TYPE_EDGE_FALLING);
++      } else {
++              pr_err("Beagle expansionboard: could not obtain gpio for KS8851_IRQ\n");
++              return;
++      }
++
++      spi_register_board_info(omap3beagle_zippy2_spi_board_info,
++                      ARRAY_SIZE(omap3beagle_zippy2_spi_board_info));
++}
++
++#else
++static inline void __init omap3beagle_ks8851_init(void) { return; }
++#endif
++
+ static struct mtd_partition omap3beagle_nand_partitions[] = {
+       /* All the partition sizes are listed in terms of NAND block size */
+       {
+@@ -674,7 +714,7 @@ static void __init omap3_beagle_init(void)
+       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       omap3_beagle_init_rev();
+-      if (!strcmp(expansionboard_name, "zippy"))
++      if ((!strcmp(expansionboard_name, "zippy")) || (!strcmp(expansionboard_name, "zippy2")))
+       {
+               pr_info("Beagle expansionboard: initializing zippy mmc\n");
+               platform_device_register(&omap_zippy_device);
+@@ -718,6 +758,12 @@ static void __init omap3_beagle_init(void)
+               omap3beagle_enc28j60_init();
+       }
++      if (!strcmp(expansionboard_name, "zippy2"))
++      {
++              pr_info("Beagle expansionboard: initializing ks_8851\n");
++              omap3beagle_ks8851_init();
++      }
++
+       usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+       usb_musb_init(NULL);
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0004-Beagle-expansion-add-trainer.patch b/src/patches/kernel/omap/beagle/expansion/0004-Beagle-expansion-add-trainer.patch
new file mode 100644 (file)
index 0000000..08ace67
--- /dev/null
@@ -0,0 +1,55 @@
+From 4d9b4e5795e322ed3efed9b8402f604e2e53cc6f Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 11 Dec 2012 06:33:24 -0600
+Subject: [PATCH 04/10] Beagle: expansion: add trainer
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 74da505..b5ed547 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -764,6 +764,37 @@ static void __init omap3_beagle_init(void)
+               omap3beagle_ks8851_init();
+       }
++      if (!strcmp(expansionboard_name, "trainer"))
++      {
++              pr_info("Beagle expansionboard: exporting GPIOs 130-141,162 to userspace\n");
++              gpio_request(130, "sysfs");
++              gpio_export(130, 1);
++              gpio_request(131, "sysfs");
++              gpio_export(131, 1);
++              gpio_request(132, "sysfs");
++              gpio_export(132, 1);
++              gpio_request(133, "sysfs");
++              gpio_export(133, 1);
++              gpio_request(134, "sysfs");
++              gpio_export(134, 1);
++              gpio_request(135, "sysfs");
++              gpio_export(135, 1);
++              gpio_request(136, "sysfs");
++              gpio_export(136, 1);
++              gpio_request(137, "sysfs");
++              gpio_export(137, 1);
++              gpio_request(138, "sysfs");
++              gpio_export(138, 1);
++              gpio_request(139, "sysfs");
++              gpio_export(139, 1);
++              gpio_request(140, "sysfs");
++              gpio_export(140, 1);
++              gpio_request(141, "sysfs");
++              gpio_export(141, 1);
++              gpio_request(162, "sysfs");
++              gpio_export(162, 1);
++      }
++
+       usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+       usb_musb_init(NULL);
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0005-Beagle-expansion-add-CircuitCo-ulcd-Support.patch b/src/patches/kernel/omap/beagle/expansion/0005-Beagle-expansion-add-CircuitCo-ulcd-Support.patch
new file mode 100644 (file)
index 0000000..8b716ee
--- /dev/null
@@ -0,0 +1,285 @@
+From a53e7913a95faefde1ee87a7ea048c04b0850066 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 11 Dec 2012 06:42:03 -0600
+Subject: [PATCH 05/10] Beagle: expansion: add CircuitCo ulcd Support
+
+This of a cleanup, squashed both ulcd commits into one:
+
+======================================================================
+
+expansion: add ulcd
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+
+======================================================================
+
+beagleboard: fix uLCD7 support
+Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
+
+======================================================================
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c          |  136 ++++++++++++++++++++++
+ drivers/video/omap2/displays/panel-generic-dpi.c |   27 +++++
+ 2 files changed, 163 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 0f9b253..b2807c2 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -118,12 +118,16 @@ static struct {
+       int dvi_pd_gpio;
+       int usr_button_gpio;
+       int mmc_caps;
++      char *lcd_driver_name;
++      int lcd_pwren;
+ } beagle_config = {
+       .mmc1_gpio_wp = -EINVAL,
+       .usb_pwr_level = 0,
+       .dvi_pd_gpio = -EINVAL,
+       .usr_button_gpio = 4,
+       .mmc_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
++      .lcd_driver_name = "",
++      .lcd_pwren = 156,
+ };
+ static struct gpio omap3_beagle_rev_gpios[] __initdata = {
+@@ -195,6 +199,7 @@ static void __init omap3_beagle_init_rev(void)
+ }
+ char expansionboard_name[16];
++char expansionboard2_name[16];
+ enum {
+       EXPANSION_MMC_NONE = 0,
+@@ -205,6 +210,7 @@ enum {
+ enum {
+       EXPANSION_I2C_NONE = 0,
+       EXPANSION_I2C_ZIPPY,
++      EXPANSION_I2C_7ULCD,
+ };
+ static struct {
+@@ -369,9 +375,53 @@ static struct omap_dss_device beagle_tv_device = {
+       .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
+ };
++static int beagle_enable_lcd(struct omap_dss_device *dssdev)
++{
++      if (gpio_is_valid(beagle_config.lcd_pwren)) {
++              pr_info("%s: Enabling LCD\n", __FUNCTION__);
++              gpio_set_value(beagle_config.lcd_pwren, 0);
++      } else {
++              pr_info("%s: Invalid LCD enable GPIO: %d\n",
++                      __FUNCTION__, beagle_config.lcd_pwren);
++      }
++
++      return 0;
++}
++
++static void beagle_disable_lcd(struct omap_dss_device *dssdev)
++{
++      if (gpio_is_valid(beagle_config.lcd_pwren)) {
++              pr_info("%s: Disabling LCD\n", __FUNCTION__);
++              gpio_set_value(beagle_config.lcd_pwren, 1);
++      } else {
++              pr_info("%s: Invalid LCD enable GPIO: %d\n",
++                      __FUNCTION__, beagle_config.lcd_pwren);
++      }
++
++      return;
++}
++
++static struct panel_generic_dpi_data lcd_panel = {
++      .name = "tfc_s9700rtwv35tr-01b",
++      .platform_enable = beagle_enable_lcd,
++      .platform_disable = beagle_disable_lcd,
++};
++
++static struct omap_dss_device beagle_lcd_device = {
++      .type                   = OMAP_DISPLAY_TYPE_DPI,
++      .name                   = "lcd",
++      .driver_name            = "generic_dpi_panel",
++      .phy.dpi.data_lines     = 24,
++      .platform_enable        = beagle_enable_lcd,
++      .platform_disable       = beagle_disable_lcd,
++      .reset_gpio             = -EINVAL,
++      .data                   = &lcd_panel,
++};
++
+ static struct omap_dss_device *beagle_dss_devices[] = {
+       &beagle_dvi_device,
+       &beagle_tv_device,
++      &beagle_lcd_device,
+ };
+ static struct omap_dss_board_info beagle_dss_data = {
+@@ -553,6 +603,53 @@ static struct i2c_board_info __initdata zippy_i2c2_rtc[] = {
+ #endif
+ };
++#if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007)
++/* Touchscreen */
++#include <linux/i2c/tsc2007.h>
++
++#define OMAP3BEAGLE_TSC2007_GPIO 157
++
++static int omap3beagle_tsc2007_get_pendown_state(void)
++{
++      return !gpio_get_value(OMAP3BEAGLE_TSC2007_GPIO);
++}
++
++static struct tsc2007_platform_data tsc2007_info = {
++      .model = 2007,
++      .x_plate_ohms = 180,
++      .get_pendown_state = omap3beagle_tsc2007_get_pendown_state,
++};
++
++static struct i2c_board_info __initdata beagle_i2c2_bbtoys_ulcd[] = {
++      {
++              I2C_BOARD_INFO("tlc59108", 0x40),
++      },
++      {
++              I2C_BOARD_INFO("tsc2007", 0x48),
++              .platform_data = &tsc2007_info,
++      },
++};
++
++static void __init omap3beagle_tsc2007_init(void)
++{
++      int r;
++
++      omap_mux_init_gpio(OMAP3BEAGLE_TSC2007_GPIO, OMAP_PIN_INPUT_PULLUP);
++
++      r = gpio_request_one(OMAP3BEAGLE_TSC2007_GPIO, GPIOF_IN, "tsc2007_pen_down");
++      if (r < 0) {
++              pr_err("Beagle expansionboard: failed to request GPIO#%d for "
++              "tsc2007 pen down IRQ\n", OMAP3BEAGLE_TSC2007_GPIO);
++              return;
++      }
++
++      beagle_i2c2_bbtoys_ulcd[0].irq = gpio_to_irq(OMAP3BEAGLE_TSC2007_GPIO);
++      irq_set_irq_type(gpio_to_irq(OMAP3BEAGLE_TSC2007_GPIO), IRQ_TYPE_EDGE_FALLING);
++}
++#else
++static struct i2c_board_info __initdata beagle_i2c2_bbtoys_ulcd[] = {};
++#endif
++
+ static int __init omap3_beagle_i2c_init(void)
+ {
+       omap3_pmic_get_config(&beagle_twldata,
+@@ -565,6 +662,10 @@ static int __init omap3_beagle_i2c_init(void)
+       omap3_pmic_init("twl4030", &beagle_twldata);
+       switch (expansion_config.i2c_settings) {
++      case EXPANSION_I2C_7ULCD:
++              omap_register_i2c_bus(2, 400,  beagle_i2c2_bbtoys_ulcd,
++                                                      ARRAY_SIZE(beagle_i2c2_bbtoys_ulcd));
++              break;
+       case EXPANSION_I2C_ZIPPY:
+               omap_register_i2c_bus(2, 400, zippy_i2c2_rtc, ARRAY_SIZE(zippy_i2c2_rtc));
+               break;
+@@ -661,6 +762,18 @@ static int __init expansionboard_setup(char *str)
+       return 0;
+ }
++static int __init expansionboard2_setup(char *str)
++{
++      if (!machine_is_omap3_beagle())
++              return 0;
++
++      if (!str)
++              return -EINVAL;
++      strncpy(expansionboard2_name, str, 16);
++      pr_info("Beagle expansionboard2: %s\n", expansionboard2_name);
++      return 0;
++}
++
+ static int __init beagle_opp_init(void)
+ {
+       int r = 0;
+@@ -726,6 +839,20 @@ static void __init omap3_beagle_init(void)
+               omap_mux_init_gpio(OMAP3BEAGLE_GPIO_ZIPPY_MMC_CD, OMAP_PIN_INPUT);
+       }
++      if (!strcmp(expansionboard2_name, "bbtoys-ulcd"))
++      {
++              int r;
++              expansion_config.i2c_settings = EXPANSION_I2C_7ULCD;
++
++              /* TODO: set lcd_driver_name by command line or device tree */
++              beagle_config.lcd_driver_name = "tfc_s9700rtwv35tr-01b",
++              lcd_panel.name = beagle_config.lcd_driver_name;
++
++              r = gpio_request_one(beagle_config.lcd_pwren, GPIOF_OUT_INIT_LOW, "LCD power");
++              if (r < 0)
++                      pr_err("Beagle expansionboard: Unable to get LCD power enable GPIO\n");
++      }
++
+       if (gpio_is_valid(beagle_config.mmc1_gpio_wp))
+               omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
+@@ -795,6 +922,14 @@ static void __init omap3_beagle_init(void)
+               gpio_export(162, 1);
+       }
++      if (!strcmp(expansionboard2_name, "bbtoys-ulcd"))
++      {
++      #if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007)
++              pr_info("Beagle expansionboard: initializing touchscreen: tsc2007\n");
++              omap3beagle_tsc2007_init();
++      #endif
++      }
++
+       usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
+       usb_musb_init(NULL);
+@@ -816,6 +951,7 @@ static void __init omap3_beagle_init(void)
+ }
+ early_param("buddy", expansionboard_setup);
++early_param("buddy2", expansionboard2_setup);
+ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+       /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
+index 97363f7..614031f 100644
+--- a/drivers/video/omap2/displays/panel-generic-dpi.c
++++ b/drivers/video/omap2/displays/panel-generic-dpi.c
+@@ -515,6 +515,33 @@ static struct panel_config generic_dpi_panels[] = {
+               },
+               .name                   = "primeview_pd104slf",
+       },
++
++      /* ThreeFiveCorp S9700RTWV35TR-01B */
++      {
++              {
++                      .x_res          = 800,
++                      .y_res          = 480,
++
++                      .pixel_clock    = 30000,
++
++                      .hsw            = 49,
++                      .hfp            = 41,
++                      .hbp            = 40,
++
++                      .vsw            = 4,
++                      .vfp            = 14,
++                      .vbp            = 29,
++
++                      .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
++                      .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
++                      .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
++                      .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
++                      .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
++              },
++              .power_on_delay         = 50,
++              .power_off_delay        = 100,
++              .name                   = "tfc_s9700rtwv35tr-01b",
++      },
+ };
+ struct panel_drv_data {
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0006-Beagle-expansion-add-wifi.patch b/src/patches/kernel/omap/beagle/expansion/0006-Beagle-expansion-add-wifi.patch
new file mode 100644 (file)
index 0000000..88d48af
--- /dev/null
@@ -0,0 +1,180 @@
+From f78cd93d767cd75969c4661723cfce46071e5b1b Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 11 Dec 2012 06:48:52 -0600
+Subject: [PATCH 06/10] Beagle: expansion: add wifi
+
+build fixes from Pantelis Antoniou <panto@antoniou-consulting.com>
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |  119 +++++++++++++++++++++++++++++++
+ 1 file changed, 119 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index a8de97e..2322d6c 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -221,6 +221,73 @@ static struct {
+       .i2c_settings = EXPANSION_I2C_NONE,
+ };
++#if IS_ENABLED(CONFIG_WL12XX)
++#include <linux/regulator/fixed.h>
++#include <linux/ti_wilink_st.h>
++#include <linux/wl12xx.h>
++
++#define OMAP_BEAGLE_WLAN_EN_GPIO    (139)
++#define OMAP_BEAGLE_BT_EN_GPIO      (138)
++#define OMAP_BEAGLE_WLAN_IRQ_GPIO   (137)
++#define OMAP_BEAGLE_FM_EN_BT_WU     (136)
++
++struct wl12xx_platform_data omap_beagle_wlan_data __initdata = {
++      .board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */
++};
++
++static struct ti_st_plat_data wilink_platform_data = {
++      .nshutdown_gpio = OMAP_BEAGLE_BT_EN_GPIO,
++      .dev_name               = "/dev/ttyO1",
++      .flow_cntrl             = 1,
++      .baud_rate              = 3000000,
++      .chip_enable    = NULL,
++      .suspend                = NULL,
++      .resume                 = NULL,
++};
++
++static struct platform_device wl12xx_device = {
++              .name           = "kim",
++              .id                     = -1,
++              .dev.platform_data = &wilink_platform_data,
++};
++
++static struct platform_device btwilink_device = {
++      .name   = "btwilink",
++      .id     = -1,
++};
++#endif
++
++static struct regulator_consumer_supply beagle_vmmc2_supply =
++      REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
++
++static struct regulator_init_data beagle_vmmc2 = {
++      .constraints = {
++              .valid_ops_mask = REGULATOR_CHANGE_STATUS,
++      },
++      .num_consumer_supplies = 1,
++      .consumer_supplies = &beagle_vmmc2_supply,
++};
++
++#if IS_ENABLED(CONFIG_WL12XX)
++static struct fixed_voltage_config beagle_vwlan = {
++      .supply_name = "vwl1271",
++      .microvolts = 1800000,  /* 1.8V */
++      .gpio = OMAP_BEAGLE_WLAN_EN_GPIO,
++      .startup_delay = 70000, /* 70ms */
++      .enable_high = 1,
++      .enabled_at_boot = 0,
++      .init_data = &beagle_vmmc2,
++};
++
++static struct platform_device omap_vwlan_device = {
++      .name           = "reg-fixed-voltage",
++      .id             = 1,
++      .dev = {
++              .platform_data = &beagle_vwlan,
++      },
++};
++#endif
++
+ //rcn-ee: this is just a fake regulator, the zippy hardware provides 3.3/1.8 with jumper..
+ static struct fixed_voltage_config beagle_vzippy = {
+       .supply_name = "vzippy",
+@@ -459,6 +526,26 @@ static struct omap2_hsmmc_info mmc_zippy[] = {
+       },
+       {}      /* Terminator */
+ };
++
++static struct omap2_hsmmc_info mmcbbt[] = {
++      {
++              .mmc            = 1,
++              .caps           = MMC_CAP_4_BIT_DATA,
++              .gpio_wp        = -EINVAL,
++              .deferred       = true,
++      },
++      {
++              .name           = "wl1271",
++              .mmc            = 2,
++              .caps           = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
++              .gpio_wp        = -EINVAL,
++              .gpio_cd        = -EINVAL,
++              .ocr_mask       = MMC_VDD_165_195,
++              .nonremovable   = true,
++      },
++      {}      /* Terminator */
++};
++
+ static struct regulator_consumer_supply beagle_vmmc1_supply[] = {
+       REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
+ };
+@@ -490,6 +577,13 @@ static int beagle_twl_gpio_setup(struct device *dev,
+       int r;
+       switch (expansion_config.mmc_settings) {
++      case EXPANSION_MMC_WIFI:
++              mmcbbt[0].gpio_wp = beagle_config.mmc1_gpio_wp;
++              /* gpio + 0 is "mmc0_cd" (input/IRQ) */
++              mmcbbt[0].gpio_cd = gpio + 0;
++
++              omap_hsmmc_late_init(mmcbbt);
++              break;
+       case EXPANSION_MMC_ZIPPY:
+               mmc_zippy[0].gpio_wp = beagle_config.mmc1_gpio_wp;
+               /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+@@ -839,6 +933,13 @@ static void __init omap3_beagle_init(void)
+               omap_mux_init_gpio(OMAP3BEAGLE_GPIO_ZIPPY_MMC_CD, OMAP_PIN_INPUT);
+       }
++      if (!strcmp(expansionboard_name, "bbtoys-wifi"))
++      {
++      #if IS_ENABLED(CONFIG_WL12XX)
++              expansion_config.mmc_settings = EXPANSION_MMC_WIFI;
++      #endif
++      }
++
+       if (!strcmp(expansionboard2_name, "bbtoys-ulcd"))
+       {
+               int r;
+@@ -857,6 +958,10 @@ static void __init omap3_beagle_init(void)
+               omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
+       switch (expansion_config.mmc_settings) {
++      case EXPANSION_MMC_WIFI:
++              mmcbbt[0].caps = beagle_config.mmc_caps;
++              omap_hsmmc_init(mmcbbt);
++              break;
+       case EXPANSION_MMC_ZIPPY:
+               mmc_zippy[0].caps = beagle_config.mmc_caps;
+               omap_hsmmc_init(mmc_zippy);
+@@ -922,6 +1027,20 @@ static void __init omap3_beagle_init(void)
+               gpio_export(162, 1);
+       }
++      if (!strcmp(expansionboard_name, "bbtoys-wifi"))
++      {
++      #if IS_ENABLED(CONFIG_WL12XX)
++              omap_beagle_wlan_data.irq = gpio_to_irq(OMAP_BEAGLE_WLAN_IRQ_GPIO);
++              if (wl12xx_set_platform_data(&omap_beagle_wlan_data))
++                      pr_err("error setting wl12xx data\n");
++              pr_info("Beagle expansionboard: registering wl12xx bt platform device\n");
++              platform_device_register(&wl12xx_device);
++              platform_device_register(&btwilink_device);
++              pr_info("Beagle expansionboard: registering wl12xx wifi platform device\n");
++              platform_device_register(&omap_vwlan_device);
++      #endif
++      }
++
+       if (!strcmp(expansionboard2_name, "bbtoys-ulcd"))
+       {
+       #if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007)
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0007-Beagle-expansion-add-beaglefpga.patch b/src/patches/kernel/omap/beagle/expansion/0007-Beagle-expansion-add-beaglefpga.patch
new file mode 100644 (file)
index 0000000..a006c7b
--- /dev/null
@@ -0,0 +1,117 @@
+From 0c361e9db10f9ec3598bf062a605a451857ee06e Mon Sep 17 00:00:00 2001
+From: Bas van der Doorn <bas@doornvd.com>
+Date: Tue, 11 Dec 2012 06:52:22 -0600
+Subject: [PATCH 07/10] Beagle: expansion: add beaglefpga
+
+Added SPI dev and McBSP 3 mux when FPGA is detected
+
+Signed-off-by: Bas van der Doorn <bas@doornvd.com>
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   76 +++++++++++++++++++++++++++++++
+ 1 file changed, 76 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 2322d6c..c257f3c 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -44,6 +44,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ #include <asm/mach/flash.h>
++#include <linux/spi/spi.h>
+ #include <video/omapdss.h>
+ #include <video/omap-panel-data.h>
+@@ -916,6 +917,68 @@ static int __init beagle_opp_init(void)
+ }
+ omap_device_initcall(beagle_opp_init);
++static void __init omap3_beagle_config_mcspi3_mux(void)
++{
++      /* NOTE: Clock pins need to be in input mode */
++      omap_mux_init_signal("sdmmc2_clk.mcspi3_clk", OMAP_PIN_INPUT);
++      omap_mux_init_signal("sdmmc2_cmd.mcspi3_simo", OMAP_PIN_OUTPUT);
++      omap_mux_init_signal("sdmmc2_dat0.mcspi3_somi", OMAP_PIN_INPUT_PULLUP);
++      omap_mux_init_signal("sdmmc2_dat2.mcspi3_cs1", OMAP_PIN_OUTPUT);
++      omap_mux_init_signal("sdmmc2_dat3.mcspi3_cs0", OMAP_PIN_OUTPUT);
++}
++
++static void __init omap3_beagle_config_mcspi4_mux(void)
++{
++      /* NOTE: Clock pins need to be in input mode */
++      omap_mux_init_signal("mcbsp1_clkr.mcspi4_clk", OMAP_PIN_INPUT);
++      omap_mux_init_signal("mcbsp1_dx.mcspi4_simo", OMAP_PIN_OUTPUT);
++      omap_mux_init_signal("mcbsp1_dr.mcspi4_somi", OMAP_PIN_INPUT_PULLUP);
++      omap_mux_init_signal("mcbsp1_fsx.mcspi4_cs0", OMAP_PIN_OUTPUT);
++}
++
++static void __init omap3_beagle_config_mcbsp3_mux(void)
++{
++      omap_mux_init_signal("mcbsp3_fsx.uart2_rx", OMAP_PIN_INPUT);
++      omap_mux_init_signal("uart2_cts.mcbsp3_dx", OMAP_PIN_OUTPUT);
++      omap_mux_init_signal("uart2_rts.mcbsp3_dr", OMAP_PIN_INPUT);
++      /* NOTE: Clock pins need to be in input mode */
++      omap_mux_init_signal("uart2_tx.mcbsp3_clkx", OMAP_PIN_INPUT);
++}
++
++static void __init omap3_beagle_config_fpga_mux(void)
++{
++      omap3_beagle_config_mcbsp3_mux();
++      omap3_beagle_config_mcspi3_mux();
++      omap3_beagle_config_mcspi4_mux();
++}
++
++static struct spi_board_info beagle_mcspi_board_info[] = {
++      /* spi 3.0 */
++      {
++              .modalias       = "spidev",
++              .max_speed_hz   = 48000000, //48 Mbps
++              .bus_num        = 3,
++              .chip_select    = 0,
++              .mode = SPI_MODE_1,
++      },
++      /* spi 3.1 */
++      {
++              .modalias       = "spidev",
++              .max_speed_hz   = 48000000, //48 Mbps
++              .bus_num        = 3,
++              .chip_select    = 1,
++              .mode = SPI_MODE_1,
++      },
++      /* spi 4.0 */
++      {
++              .modalias       = "spidev",
++              .max_speed_hz   = 48000000, //48 Mbps
++              .bus_num        = 4,
++              .chip_select    = 0,
++              .mode = SPI_MODE_1,
++      },
++};
++
+ static void __init omap3_beagle_init(void)
+ {
+       omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+@@ -1041,6 +1104,19 @@ static void __init omap3_beagle_init(void)
+       #endif
+       }
++      if (!strcmp(expansionboard_name, "beaglefpga"))
++      {
++      #if IS_ENABLED(CONFIG_SPI_SPIDEV)
++              pr_info("Beagle expansionboard: enabling SPIdev for McSPI3/4 and pin muxing for McBSP3 slave mode\n");
++
++              /* FPGA pin settings configure McSPI 3, McSPI 4 and McBSP 3 */
++              omap3_beagle_config_fpga_mux();
++
++              /* register McSPI 3 and McSPI 4 for FPGA programming and control */
++              spi_register_board_info(beagle_mcspi_board_info, ARRAY_SIZE(beagle_mcspi_board_info));
++      #endif
++      }
++
+       if (!strcmp(expansionboard2_name, "bbtoys-ulcd"))
+       {
+       #if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007)
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0008-Beagle-expansion-add-spidev.patch b/src/patches/kernel/omap/beagle/expansion/0008-Beagle-expansion-add-spidev.patch
new file mode 100644 (file)
index 0000000..23cc525
--- /dev/null
@@ -0,0 +1,35 @@
+From 5258354e6e4d0b55334099868668a166d967c1d2 Mon Sep 17 00:00:00 2001
+From: Russell Hay <russell.hay@gmail.com>
+Date: Tue, 11 Dec 2012 06:53:58 -0600
+Subject: [PATCH 08/10] Beagle: expansion: add spidev
+
+Signed-off-by: Russell Hay <russell.hay@gmail.com>
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index c257f3c..3e0313ee 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -1117,6 +1117,16 @@ static void __init omap3_beagle_init(void)
+       #endif
+       }
++      if (!strcmp(expansionboard_name, "spidev"))
++      {
++      #if IS_ENABLED(CONFIG_SPI_SPIDEV)
++              pr_info("Beagle expansionboard: registering spidev\n");
++              omap3_beagle_config_mcspi3_mux();
++              omap3_beagle_config_mcspi4_mux();
++              spi_register_board_info(beagle_mcspi_board_info, ARRAY_SIZE(beagle_mcspi_board_info));
++      #endif
++      }
++
+       if (!strcmp(expansionboard2_name, "bbtoys-ulcd"))
+       {
+       #if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007)
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0009-Beagle-expansion-add-Aptina-li5m03-camera.patch b/src/patches/kernel/omap/beagle/expansion/0009-Beagle-expansion-add-Aptina-li5m03-camera.patch
new file mode 100644 (file)
index 0000000..28d2d4a
--- /dev/null
@@ -0,0 +1,217 @@
+From cc6ced0a1cbaea65a507ec3fe543a5b98d760d23 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 11 Dec 2012 06:58:15 -0600
+Subject: [PATCH 09/10] Beagle: expansion: add Aptina li5m03 camera
+
+Based on:
+https://github.com/Aptina/BeagleBoard-xM/blob/master/tools/0266-Adding-MT9P031-Support-files.patch
+
+And on Max Galemin's patch
+https://github.com/MaxGalemin/buildroot/blob/master/board/beagleboard/xm/kernel-patches/linux-0003-Add-support-for-MT9P031-Aptina-image-sensor-driver.patch
+
+And Koen Kooi Previous work's
+https://github.com/beagleboard/kernel/blob/beagleboard-3.2/patches/camera/0003-beagleboard-fix-i2c2-init.patch
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |  142 +++++++++++++++++++++++++++++++
+ 1 file changed, 142 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 3e0313ee..4fb5eae 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -201,6 +201,7 @@ static void __init omap3_beagle_init_rev(void)
+ char expansionboard_name[16];
+ char expansionboard2_name[16];
++char camera_name[16];
+ enum {
+       EXPANSION_MMC_NONE = 0,
+@@ -555,6 +556,14 @@ static struct regulator_consumer_supply beagle_vsim_supply[] = {
+       REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"),
+ };
++static struct regulator_consumer_supply beagle_vaux3_supply = {
++      .supply         = "cam_1v8",
++};
++
++static struct regulator_consumer_supply beagle_vaux4_supply = {
++      .supply         = "cam_2v8",
++};
++
+ static struct gpio_led gpio_leds[];
+ /* PHY's VCC regulator might be added later, so flag that we need it */
+@@ -677,11 +686,43 @@ static struct regulator_init_data beagle_vsim = {
+       .consumer_supplies      = beagle_vsim_supply,
+ };
++/* VAUX3 for CAM_1V8 */
++static struct regulator_init_data beagle_vaux3 = {
++      .constraints = {
++              .min_uV                 = 1800000,
++              .max_uV                 = 1800000,
++              .apply_uV               = true,
++              .valid_modes_mask       = REGULATOR_MODE_NORMAL
++                                      | REGULATOR_MODE_STANDBY,
++              .valid_ops_mask         = REGULATOR_CHANGE_MODE
++                                      | REGULATOR_CHANGE_STATUS,
++      },
++      .num_consumer_supplies  = 1,
++      .consumer_supplies      = &beagle_vaux3_supply,
++};
++
++/* VAUX4 for CAM_2V8 */
++static struct regulator_init_data beagle_vaux4 = {
++      .constraints = {
++              .min_uV                 = 1800000,
++              .max_uV                 = 1800000,
++              .apply_uV               = true,
++              .valid_modes_mask       = REGULATOR_MODE_NORMAL
++                                      | REGULATOR_MODE_STANDBY,
++              .valid_ops_mask         = REGULATOR_CHANGE_MODE
++                                      | REGULATOR_CHANGE_STATUS,
++      },
++      .num_consumer_supplies  = 1,
++      .consumer_supplies      = &beagle_vaux4_supply,
++};
++
+ static struct twl4030_platform_data beagle_twldata = {
+       /* platform_data for children goes here */
+       .gpio           = &beagle_gpio_data,
+       .vmmc1          = &beagle_vmmc1,
+       .vsim           = &beagle_vsim,
++      .vaux3          = &beagle_vaux3,
++      .vaux4          = &beagle_vaux4,
+ };
+ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+@@ -745,6 +786,61 @@ static void __init omap3beagle_tsc2007_init(void)
+ static struct i2c_board_info __initdata beagle_i2c2_bbtoys_ulcd[] = {};
+ #endif
++#if IS_ENABLED(CONFIG_VIDEO_MT9P031)
++/* needed for: omap3_beagle_late_initcall */
++#include "devices.h"
++#include <media/omap3isp.h>
++#include <media/mt9p031.h>
++/* needed for: v4l2_dev_to_isp_device */
++#include "../../../drivers/media/platform/omap3isp/isp.h"
++
++#define MT9P031_RESET_GPIO    98
++#define MT9P031_EXT_FREQ      21000000
++#define MT9P031_TARGET_FREQ   48000000
++
++#define MT9P031_I2C_ADDR      0x48
++#define MT9P031_I2C_BUS               2
++
++static struct regulator *reg_1v8, *reg_2v8;
++
++static struct mt9p031_platform_data beagle_mt9p031_platform_data = {
++      .reset          = MT9P031_RESET_GPIO,
++      .ext_freq       = MT9P031_EXT_FREQ,
++      .target_freq    = MT9P031_TARGET_FREQ,
++};
++
++static struct i2c_board_info mt9p031_camera_i2c_device = {
++      I2C_BOARD_INFO("mt9p031", MT9P031_I2C_ADDR),
++      .platform_data = &beagle_mt9p031_platform_data,
++};
++
++static struct isp_subdev_i2c_board_info mt9p031_camera_subdevs[] = {
++      {
++              .board_info = &mt9p031_camera_i2c_device,
++              .i2c_adapter_id = MT9P031_I2C_BUS,
++      },
++      { NULL, 0, },
++};
++
++static struct isp_v4l2_subdevs_group beagle_camera_subdevs[] = {
++      {
++              .subdevs = mt9p031_camera_subdevs,
++              .interface = ISP_INTERFACE_PARALLEL,
++              .bus = {
++                      .parallel = {
++                              .data_lane_shift = 0,
++                              .clk_pol = 1,
++                      }
++              },
++      },
++      { },
++};
++
++static struct isp_platform_data beagle_isp_platform_data = {
++      .subdevs = beagle_camera_subdevs,
++};
++#endif
++
+ static int __init omap3_beagle_i2c_init(void)
+ {
+       omap3_pmic_get_config(&beagle_twldata,
+@@ -869,6 +965,18 @@ static int __init expansionboard2_setup(char *str)
+       return 0;
+ }
++static int __init camera_setup(char *str)
++{
++      if (!machine_is_omap3_beagle())
++              return 0;
++
++      if (!str)
++              return -EINVAL;
++      strncpy(camera_name, str, 16);
++      pr_info("Beagle camera: %s\n", camera_name);
++      return 0;
++}
++
+ static int __init beagle_opp_init(void)
+ {
+       int r = 0;
+@@ -1155,8 +1263,42 @@ static void __init omap3_beagle_init(void)
+       pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup));
+ }
++static int __init omap3_beagle_late_initcall(void)
++{
++      if (!machine_is_omap3_beagle())
++              return 0;
++
++      if (!cpu_is_omap3630())
++              return 0;
++
++#if IS_ENABLED(CONFIG_VIDEO_MT9P031)
++      if ((!strcmp(camera_name, "lbcm5m1")) || (!strcmp(camera_name, "li5m03")))
++      {
++              pr_info("Beagle camera: MT9P031 init\n");
++
++              reg_1v8 = regulator_get(NULL, "cam_1v8");
++              if (IS_ERR(reg_1v8))
++                      pr_err("%s: cannot get cam_1v8 regulator\n", __func__);
++              else
++                      regulator_enable(reg_1v8);
++
++              reg_2v8 = regulator_get(NULL, "cam_2v8");
++              if (IS_ERR(reg_2v8))
++                      pr_err("%s: cannot get cam_2v8 regulator\n", __func__);
++              else
++                      regulator_enable(reg_2v8);
++
++              omap3_init_camera(&beagle_isp_platform_data);
++      }
++#endif
++      return 0;
++}
++
+ early_param("buddy", expansionboard_setup);
+ early_param("buddy2", expansionboard2_setup);
++early_param("camera", camera_setup);
++
++late_initcall(omap3_beagle_late_initcall);
+ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+       /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0010-Beagle-expansion-add-LSR-COM6L-Adapter-Board.patch b/src/patches/kernel/omap/beagle/expansion/0010-Beagle-expansion-add-LSR-COM6L-Adapter-Board.patch
new file mode 100644 (file)
index 0000000..04a3656
--- /dev/null
@@ -0,0 +1,123 @@
+From f2e2294733d926e627dcda6425f58611b185c7fc Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 11 Dec 2012 07:02:40 -0600
+Subject: [PATCH 10/10] Beagle: expansion: add LSR COM6L Adapter Board
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   60 ++++++++++++++++++++++++++++---
+ 1 file changed, 55 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 0ac1b49..5a7e7b5 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -202,6 +202,7 @@ static void __init omap3_beagle_init_rev(void)
+ char expansionboard_name[16];
+ char expansionboard2_name[16];
+ char camera_name[16];
++char wl12xx_name[16];
+ enum {
+       EXPANSION_MMC_NONE = 0,
+@@ -237,6 +238,10 @@ struct wl12xx_platform_data omap_beagle_wlan_data __initdata = {
+       .board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */
+ };
++struct wl12xx_platform_data omap_beagle_wlan_data_26mhz __initdata = {
++      .board_ref_clock = WL12XX_REFCLOCK_26, /* 26 MHz */
++};
++
+ static struct ti_st_plat_data wilink_platform_data = {
+       .nshutdown_gpio = OMAP_BEAGLE_BT_EN_GPIO,
+       .dev_name               = "/dev/ttyO1",
+@@ -987,6 +992,18 @@ static int __init camera_setup(char *str)
+       return 0;
+ }
++static int __init wl12xx_setup(char *str)
++{
++      if (!machine_is_omap3_beagle())
++              return 0;
++
++      if (!str)
++              return -EINVAL;
++      strncpy(wl12xx_name, str, 16);
++      pr_info("Beagle wl12xx clk: %s\n", wl12xx_name);
++      return 0;
++}
++
+ static int __init beagle_opp_init(void)
+ {
+       int r = 0;
+@@ -1114,9 +1131,29 @@ static void __init omap3_beagle_init(void)
+               omap_mux_init_gpio(OMAP3BEAGLE_GPIO_ZIPPY_MMC_CD, OMAP_PIN_INPUT);
+       }
+-      if (!strcmp(expansionboard_name, "bbtoys-wifi"))
++      if ((!strcmp(expansionboard_name, "bbtoys-wifi")) || (!strcmp(expansionboard_name, "lsr-com6l-adpt")))
+       {
+       #if IS_ENABLED(CONFIG_WL12XX)
++              pr_info("Beagle expansion: wl12xx: setting up gpio pinmux\n");
++
++              omap_mux_init_gpio(OMAP_BEAGLE_FM_EN_BT_WU, OMAP_PIN_OUTPUT);
++              omap_mux_init_gpio(OMAP_BEAGLE_BT_EN_GPIO, OMAP_PIN_OUTPUT);
++              omap_mux_init_gpio(OMAP_BEAGLE_WLAN_EN_GPIO, OMAP_PIN_OUTPUT);
++
++              omap_mux_init_gpio(OMAP_BEAGLE_WLAN_IRQ_GPIO, OMAP_PIN_INPUT_PULLUP);
++
++              /* WLAN SDIO: MMC2 CLK */
++              omap_mux_init_signal("sdmmc2_clk.sdmmc2_clk", OMAP_PIN_INPUT_PULLUP);
++
++              /* WLAN SDIO: MMC2 CMD */
++              omap_mux_init_signal("sdmmc2_cmd.sdmmc2_cmd", OMAP_PIN_INPUT_PULLUP);
++
++              /* WLAN SDIO: MMC2 DAT[0-3] */
++              omap_mux_init_signal("sdmmc2_dat0.sdmmc2_dat0", OMAP_PIN_INPUT_PULLUP);
++              omap_mux_init_signal("sdmmc2_dat1.sdmmc2_dat1", OMAP_PIN_INPUT_PULLUP);
++              omap_mux_init_signal("sdmmc2_dat2.sdmmc2_dat2", OMAP_PIN_INPUT_PULLUP);
++              omap_mux_init_signal("sdmmc2_dat3.sdmmc2_dat3", OMAP_PIN_INPUT_PULLUP);
++
+               expansion_config.mmc_settings = EXPANSION_MMC_WIFI;
+       #endif
+       }
+@@ -1208,12 +1245,24 @@ static void __init omap3_beagle_init(void)
+               gpio_export(162, 1);
+       }
+-      if (!strcmp(expansionboard_name, "bbtoys-wifi"))
++      if ((!strcmp(expansionboard_name, "bbtoys-wifi")) || (!strcmp(expansionboard_name, "lsr-com6l-adpt")))
+       {
+       #if IS_ENABLED(CONFIG_WL12XX)
+-              omap_beagle_wlan_data.irq = gpio_to_irq(OMAP_BEAGLE_WLAN_IRQ_GPIO);
+-              if (wl12xx_set_platform_data(&omap_beagle_wlan_data))
+-                      pr_err("error setting wl12xx data\n");
++              pr_info("Beagle expansionboard: initializing wl12xx platform\n");
++
++              if (!strcmp(wl12xx_name, "wl12xx_26mhz")) {
++                      pr_info("wl12xx: 26Mhz reference clock (TiWi5)\n");
++                      omap_beagle_wlan_data_26mhz.irq = gpio_to_irq(OMAP_BEAGLE_WLAN_IRQ_GPIO);
++                      if (wl12xx_set_platform_data(&omap_beagle_wlan_data_26mhz))
++                              pr_err("error setting wl12xx data\n");
++              } else {
++                      pr_info("wl12xx: 38.4Mhz reference clock (TiWi2/TiWi-BLE)\n");
++                      pr_info("wl12xx: for (TiWi5) support pass kernel [wl12xx_clk=wl12xx_26mhz]\n");
++                      omap_beagle_wlan_data.irq = gpio_to_irq(OMAP_BEAGLE_WLAN_IRQ_GPIO);
++                      if (wl12xx_set_platform_data(&omap_beagle_wlan_data))
++                              pr_err("error setting wl12xx data\n");
++              }
++
+               pr_info("Beagle expansionboard: registering wl12xx bt platform device\n");
+               platform_device_register(&wl12xx_device);
+               platform_device_register(&btwilink_device);
+@@ -1307,6 +1356,7 @@ static int __init omap3_beagle_late_initcall(void)
+ early_param("buddy", expansionboard_setup);
+ early_param("buddy2", expansionboard2_setup);
+ early_param("camera", camera_setup);
++early_param("wl12xx_clk", wl12xx_setup);
+ late_initcall(omap3_beagle_late_initcall);
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0011-Beagle-expansion-LSR-COM6L-Adapter-Board-also-initia.patch b/src/patches/kernel/omap/beagle/expansion/0011-Beagle-expansion-LSR-COM6L-Adapter-Board-also-initia.patch
new file mode 100644 (file)
index 0000000..a8edc77
--- /dev/null
@@ -0,0 +1,73 @@
+From 89eb49ac0268518799984fa035ac3fea0ae758ec Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Mon, 21 Jan 2013 11:52:20 -0600
+Subject: [PATCH 11/11] Beagle: expansion: LSR COM6L Adapter Board also
+ initialize the 24c256 eeprom
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 5a7e7b5..6797488 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -39,6 +39,7 @@
+ #include <linux/regulator/machine.h>
+ #include <linux/regulator/fixed.h>
+ #include <linux/i2c/twl.h>
++#include <linux/i2c/at24.h>
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -214,6 +215,7 @@ enum {
+       EXPANSION_I2C_NONE = 0,
+       EXPANSION_I2C_ZIPPY,
+       EXPANSION_I2C_7ULCD,
++      EXPANSION_I2C_COM6L,
+ };
+ static struct {
+@@ -856,6 +858,20 @@ static struct isp_platform_data beagle_isp_platform_data = {
+ };
+ #endif
++static struct at24_platform_data beagle_at24_eeprom_info = {
++      .byte_len       = (256*1024) / 8,
++      .page_size      = 64,
++      .flags          = AT24_FLAG_ADDR16,
++      .context        = (void *)NULL,
++};
++
++static struct i2c_board_info __initdata com6l_adpt_eeprom[] = {
++      {
++              I2C_BOARD_INFO("24c256", 0x50),
++              .platform_data  = &beagle_at24_eeprom_info,
++      },
++};
++
+ static int __init omap3_beagle_i2c_init(void)
+ {
+       omap3_pmic_get_config(&beagle_twldata,
+@@ -875,6 +891,9 @@ static int __init omap3_beagle_i2c_init(void)
+       case EXPANSION_I2C_ZIPPY:
+               omap_register_i2c_bus(2, 400, zippy_i2c2_rtc, ARRAY_SIZE(zippy_i2c2_rtc));
+               break;
++      case EXPANSION_I2C_COM6L:
++              omap_register_i2c_bus(2, 400, com6l_adpt_eeprom, ARRAY_SIZE(com6l_adpt_eeprom));
++              break;
+       default:
+               omap_register_i2c_bus(2, 400, NULL, 0);
+       }
+@@ -1155,6 +1174,7 @@ static void __init omap3_beagle_init(void)
+               omap_mux_init_signal("sdmmc2_dat3.sdmmc2_dat3", OMAP_PIN_INPUT_PULLUP);
+               expansion_config.mmc_settings = EXPANSION_MMC_WIFI;
++              expansion_config.i2c_settings = EXPANSION_I2C_COM6L;
+       #endif
+       }
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/beagle/expansion/0011-WIP-Beagle-expansion-extend-spidev-to-uart2.patch b/src/patches/kernel/omap/beagle/expansion/0011-WIP-Beagle-expansion-extend-spidev-to-uart2.patch
new file mode 100644 (file)
index 0000000..2039e4a
--- /dev/null
@@ -0,0 +1,43 @@
+From d78f1a01cc52ebad5d59edad772f2b403bfe67bd Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Wed, 12 Dec 2012 11:34:29 -0600
+Subject: [PATCH 11/11] WIP: Beagle: expansion: extend spidev to uart2
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap3beagle.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
+index 4fa880a..e4cfd5f 100644
+--- a/arch/arm/mach-omap2/board-omap3beagle.c
++++ b/arch/arm/mach-omap2/board-omap3beagle.c
+@@ -1162,6 +1162,16 @@ static void __init omap3_beagle_init(void)
+       if (gpio_is_valid(beagle_config.dvi_pd_gpio))
+               omap_mux_init_gpio(beagle_config.dvi_pd_gpio, OMAP_PIN_OUTPUT);
+       omap_display_init(&beagle_dss_data);
++
++      if (!strcmp(expansionboard_name, "spidev"))
++      {
++              pr_info("Beagle expansion: spidev: enable uart2/ttyO1\n");
++              omap_mux_init_signal("uart2_tx.uart2_tx", OMAP_PIN_OUTPUT);
++              omap_mux_init_signal("uart2_rts.uart2_rts", OMAP_PIN_OUTPUT);
++              omap_mux_init_signal("uart2_cts.uart2_cts", OMAP_PIN_INPUT);
++              omap_mux_init_signal("mcbsp3_fsx.uart2_rx", OMAP_PIN_INPUT);
++      }
++
+       omap_serial_init();
+       omap_sdrc_init(mt46h32m32lf6_sdrc_params,
+                                 mt46h32m32lf6_sdrc_params);
+@@ -1248,7 +1258,7 @@ static void __init omap3_beagle_init(void)
+       if (!strcmp(expansionboard_name, "spidev"))
+       {
+-              pr_info("Beagle expansionboard: registering spidev\n");
++              pr_info("Beagle expansionboard: spidev: enabling spi3/spi4\n");
+               omap3_beagle_config_mcspi3_mux();
+               omap3_beagle_config_mcspi4_mux();
+               spi_register_board_info(beagle_mcspi_board_info, ARRAY_SIZE(beagle_mcspi_board_info));
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0001-panda-fix-wl12xx-regulator.patch b/src/patches/kernel/omap/panda/0001-panda-fix-wl12xx-regulator.patch
new file mode 100644 (file)
index 0000000..de0e84b
--- /dev/null
@@ -0,0 +1,27 @@
+From a3abd1593e381deb4b1f358a55069988996eeae4 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Tue, 2 Aug 2011 21:55:34 -0500
+Subject: [PATCH 1/2] panda: fix wl12xx regulator
+
+pulled from: http://elinux.org/Panda_How_to_kernel_3_0_rel
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/twl-common.c |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
+index e49b40b..0fd1a70 100644
+--- a/arch/arm/mach-omap2/twl-common.c
++++ b/arch/arm/mach-omap2/twl-common.c
+@@ -360,6 +360,7 @@ static struct regulator_init_data omap4_vusb_idata = {
+ static struct regulator_init_data omap4_clk32kg_idata = {
+       .constraints = {
+               .valid_ops_mask         = REGULATOR_CHANGE_STATUS,
++              .always_on              = true,
+       },
+ };
+-- 
+1.7.7.6
+
diff --git a/src/patches/kernel/omap/panda/0002-ti-st-st-kim-fixing-firmware-path.patch b/src/patches/kernel/omap/panda/0002-ti-st-st-kim-fixing-firmware-path.patch
new file mode 100644 (file)
index 0000000..694bc36
--- /dev/null
@@ -0,0 +1,36 @@
+From 8de5d11f076ee25182df805ab78e0823ce4dd2be Mon Sep 17 00:00:00 2001
+From: Ricardo Salveti de Araujo <ricardo.salveti@linaro.org>
+Date: Tue, 25 Oct 2011 10:06:39 +0200
+Subject: [PATCH 2/2] ti-st/st-kim: fixing firmware path
+
+Signed-off-by: Ricardo Salveti de Araujo <ricardo.salveti@linaro.org>
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/misc/ti-st/st_kim.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
+index 9ff942a..f673464 100644
+--- a/drivers/misc/ti-st/st_kim.c
++++ b/drivers/misc/ti-st/st_kim.c
+@@ -244,7 +244,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
+       if (version & 0x8000)
+               maj_ver |= 0x0008;
+-      sprintf(bts_scr_name, "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
++      sprintf(bts_scr_name, "ti-connectivity/TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
+       /* to be accessed later via sysfs entry */
+       kim_gdata->version.full = version;
+@@ -287,7 +287,7 @@ static long download_firmware(struct kim_data_s *kim_gdata)
+       long len = 0;
+       unsigned char *ptr = NULL;
+       unsigned char *action_ptr = NULL;
+-      unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */
++      unsigned char bts_scr_name[50] = { 0 }; /* 50 char long bts scr name? */
+       int wr_room_space;
+       int cmd_size;
+       unsigned long timeout;
+-- 
+1.7.7.6
+
diff --git a/src/patches/kernel/omap/panda/0003-Panda-expansion-add-spidev.patch b/src/patches/kernel/omap/panda/0003-Panda-expansion-add-spidev.patch
new file mode 100644 (file)
index 0000000..9369852
--- /dev/null
@@ -0,0 +1,112 @@
+From 3304f2feba4999fc1013911f0cf0d9acc33a0117 Mon Sep 17 00:00:00 2001
+From: Adrien Ferre <ferre.adrien@gmail.com>
+Date: Mon, 25 Mar 2013 12:00:38 -0500
+Subject: [PATCH 3/3] Panda: expansion: add spidev
+
+I've made a patch to enable spidev on pandaboards using buddy=spidev just like for beagle.
+
+https://github.com/RobertCNelson/stable-kernel/issues/22
+
+Signed-off-by: Adrien Ferre <ferre.adrien@gmail.com>
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap4panda.c |   43 ++++++++++++++++++++++++++++++++
+ 1 file changed, 43 insertions(+)
+
+diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
+index 1e2c75e..3563f86 100644
+--- a/arch/arm/mach-omap2/board-omap4panda.c
++++ b/arch/arm/mach-omap2/board-omap4panda.c
+@@ -22,6 +22,7 @@
+ #include <linux/clk.h>
+ #include <linux/io.h>
+ #include <linux/leds.h>
++#include <linux/irq.h>
+ #include <linux/gpio.h>
+ #include <linux/usb/otg.h>
+ #include <linux/i2c/twl.h>
+@@ -35,6 +36,7 @@
+ #include <linux/wl12xx.h>
+ #include <linux/irqchip/arm-gic.h>
+ #include <linux/platform_data/omap-abe-twl6040.h>
++#include <linux/spi/spi.h>
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+@@ -54,6 +56,8 @@
+ #define GPIO_WIFI_PMENA               43
+ #define GPIO_WIFI_IRQ         53
++char expboard_name[16];
++
+ /* wl127x BT, FM, GPS connectivity chip */
+ static struct ti_st_plat_data wilink_platform_data = {
+       .nshutdown_gpio = 46,
+@@ -99,6 +103,25 @@ static struct platform_device leds_gpio = {
+       },
+ };
++static struct spi_board_info panda_mcspi_board_info[] = {
++      /* spi 1.0 */
++      {
++              .modalias       = "spidev",
++              .max_speed_hz   = 48000000, //48 Mbps
++              .bus_num        = 1,
++              .chip_select    = 0,
++              .mode = SPI_MODE_1,
++      },
++      /* spi 1.1 */
++      {
++              .modalias       = "spidev",
++              .max_speed_hz   = 48000000, //48 Mbps
++              .bus_num        = 1,
++              .chip_select    = 1,
++              .mode = SPI_MODE_1,
++      },
++};
++
+ static struct omap_abe_twl6040_data panda_abe_audio_data = {
+       /* Audio out */
+       .has_hs         = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
+@@ -161,6 +184,18 @@ static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
+       .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
+ };
++static int __init expansionboard_setup(char *str)
++{
++      if (!machine_is_omap4_panda())
++              return 0;
++
++      if (!str)
++              return -EINVAL;
++      strncpy(expboard_name, str, 16);
++      pr_info("Panda expansionboard: %s\n", expboard_name);
++      return 0;
++}
++
+ static void __init omap4_ehci_init(void)
+ {
+       int ret;
+@@ -435,11 +470,19 @@ static void __init omap4_panda_init(void)
+       omap_sdrc_init(NULL, NULL);
+       omap4_twl6030_hsmmc_init(mmc);
+       omap4_ehci_init();
++      if (!strcmp(expboard_name, "spidev")) {
++      #if IS_ENABLED(CONFIG_SPI_SPIDEV)
++              pr_info("Panda expansionboard: spidev: enabling spi3/spi4\n");
++              spi_register_board_info(panda_mcspi_board_info, ARRAY_SIZE(panda_mcspi_board_info));
++      #endif
++      }
+       usb_bind_phy("musb-hdrc.2.auto", 0, "omap-usb2.3.auto");
+       usb_musb_init(&musb_board_data);
+       omap4_panda_display_init();
+ }
++early_param("buddy", expansionboard_setup);
++
+ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
+       /* Maintainer: David Anders - Texas Instruments Inc */
+       .atag_offset    = 0x100,
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0004-HACK-PandaES-disable-cpufreq-so-board-will-boot.patch b/src/patches/kernel/omap/panda/0004-HACK-PandaES-disable-cpufreq-so-board-will-boot.patch
new file mode 100644 (file)
index 0000000..12194e4
--- /dev/null
@@ -0,0 +1,38 @@
+From 359104632fa556e3c5c78e4016c2585896225716 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Mon, 1 Apr 2013 12:17:50 -0500
+Subject: [PATCH 4/4] HACK: PandaES: disable cpufreq so board will boot
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/cpufreq/omap-cpufreq.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
+index 0279d18..0a8ac09 100644
+--- a/drivers/cpufreq/omap-cpufreq.c
++++ b/drivers/cpufreq/omap-cpufreq.c
+@@ -31,6 +31,8 @@
+ #include <asm/smp_plat.h>
+ #include <asm/cpu.h>
++#include "../../arch/arm/mach-omap2/soc.h"
++
+ /* OPP tolerance in percentage */
+ #define       OPP_TOLERANCE   4
+@@ -246,6 +248,11 @@ static struct cpufreq_driver omap_driver = {
+ static int omap_cpufreq_probe(struct platform_device *pdev)
+ {
++      if (cpu_is_omap446x()) {
++              pr_err("%s: unsupported Silicon?\n", __func__);
++              return -EINVAL;
++      }
++
+       mpu_dev = get_cpu_device(0);
+       if (!mpu_dev) {
+               pr_warning("%s: unable to get the mpu device\n", __func__);
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0006-ARM-hw_breakpoint-Enable-debug-powerdown-only-if-sys.patch b/src/patches/kernel/omap/panda/0006-ARM-hw_breakpoint-Enable-debug-powerdown-only-if-sys.patch
new file mode 100644 (file)
index 0000000..fa64934
--- /dev/null
@@ -0,0 +1,122 @@
+From 76c1d8cdfa0967b04ca8168a77bb101d4ea71150 Mon Sep 17 00:00:00 2001
+From: Santosh Shilimkar <santosh.shilimkar@ti.com>
+Date: Mon, 18 Mar 2013 06:51:30 +0000
+Subject: [PATCH 6/6] ARM: hw_breakpoint: Enable debug powerdown only if
+ system supports 'has_ossr'
+
+On Friday 15 March 2013 10:30 AM, Will Deacon wrote:
+> On Thu, Mar 14, 2013 at 01:08:00PM +0530, Santosh Shilimkar wrote:
+>> Will,
+>
+> Hi guys,
+>
+> I'm out of the office at the moment and have really terrible connectivity,
+> so I can't do too much until next week. However, I don't think adding the
+> has_ossr check is the right fix for this problem.
+>
+>> On Wednesday 13 March 2013 05:59 PM, Lokesh Vutla wrote:
+>>> Hi Dietmar,
+>>> On Wednesday 13 March 2013 05:35 PM, Dietmar Eggemann wrote:
+>>>> On 13/03/13 06:52, Lokesh Vutla wrote:
+>>>>> Commit {9a6eb31 ARM: hw_breakpoint: Debug powerdown support for
+>>>>> self-hosted
+>>>>> debug} introduces debug powerdown support for self-hosted debug.
+>>>>> While merging the patch 'has_ossr' check was removed which
+>>>>> was needed for hardwares which doesn't support self-hosted debug.
+>>>>> Pandaboard (A9) is one such hardware and Dietmar's orginial
+>>>>> patch did mention this issue.
+>>>>> Without that check on Panda with CPUIDLE enabled, a flood of
+>>>>> below messages thrown.
+>>>>>
+>>>>> [ 3.597930] hw-breakpoint: CPU 0 failed to disable vector catch
+>>>>> [ 3.597991] hw-breakpoint: CPU 1 failed to disable vector catch
+>
+> Ok, so this means that we've taken an undefined instruction exception while
+> trying to reset the debug registers on the PM_EXIT path. Now, the code there
+> deals with CPUs that don't have the save/restore registers just fine, so
+> that shouldn't have anything to do with this problem, particularly if the
+> bit that is tripping us up is related to clearing vector catch.
+>
+Agree.
+
+> Furthermore, I was under the impression that hw_breakpoint did actually
+> work on panda, which implies that a cold boot *does* manage to reset the
+> registers (can you please confirm this by looking in your dmesg during
+> boot?). In that case, it seems as though a PM cycle is powering down a
+> bunch of debug logic that was powered up during boot, and then we trip over
+> because we can't access the register bank.
+>
+Actually it seems to be without PM. Thanks to analysis from Lokesh, the issue
+can be seen even with just suspend or cpu hotplug. So cold boot as such is
+fine.
+
+> The proper solution to this problem requires us to establish exactly what is
+> turning off the debug registers, and then having an OMAP PM notifier to
+> enable it again. Assuming this has always been the case, I expect hardware
+> debug across PM fails silently with older kernels.
+>
+This has been always the case it seems with CPU power cycle.
+After the CPU is power cycled, 'DBGAUTHSTATUS' reads '0xaa' rather
+than '0xaf' which means 'DBGEN = 0' and hence code fails to enable
+monitor mode. This happens on both secure and GP devices and it can not
+be patched since the secure code is ROM'ed. We didn't notice so far
+because hw_breakpoint support was not default enabled on OMAP till the
+multi-platform build.
+
+>> I was also wondering whether we should just warn once rather
+>> than continuous warnings in the notifier. Patch is end of the
+>> email.
+>
+> Could do, but I'd like to see a fix for the real issue before we simply hide
+> the warnings :)
+>
+Agree here too. As evident above, the feature won't work on OMAP4
+devices with PM and hence some solution is needed.
+
+What you think of below ?
+
+>From d74b4264f6a5967b0f7ada96aad77ab0ac30dbed Mon Sep 17 00:00:00 2001
+From: Santosh Shilimkar <santosh.shilimkar@ti.com>
+Date: Mon, 18 Mar 2013 11:59:04 +0530
+Subject: [PATCH] ARM: hw_breakpoints: Check for CPU debug availability before
+ enabling it
+
+CPU debug features like hardware break, watchpoints can be used only when
+the debug mode is enabled and available for non-secure mode.
+
+Hence check 'DBGAUTHSTATUS.DBGEN' before proceeding to enable the
+features.
+
+Thanks to Will for pointers and Lokesh for the analysis of the issue on
+OMAP4 where after a CPU power cycle, debug mode gets disabled.
+
+Cc: Will Deacon <Will.Deacon@arm.com>
+
+Tested-by: Lokesh Vutla <lokeshvutla@ti.com>
+Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
+---
+ arch/arm/kernel/hw_breakpoint.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
+index 96093b7..683a7cf 100644
+--- a/arch/arm/kernel/hw_breakpoint.c
++++ b/arch/arm/kernel/hw_breakpoint.c
+@@ -930,6 +930,14 @@ static void reset_ctrl_regs(void *unused)
+       int i, raw_num_brps, err = 0, cpu = smp_processor_id();
+       u32 val;
++      /* Check if we have access to CPU debug features */
++      ARM_DBG_READ(c7, c14, 6, val);
++      if ((val & 0x1) == 0) {
++              pr_warn_once("CPU %d debug is unavailable\n", cpu);
++              cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu));
++              return;
++      }
++
+       /*
+        * v7 debug contains save and restore registers so that debug state
+        * can be maintained across low-power modes without leaving the debug
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0007-Revert-regulator-twl-Remove-TWL6030_FIXED_RESOURCE.patch b/src/patches/kernel/omap/panda/0007-Revert-regulator-twl-Remove-TWL6030_FIXED_RESOURCE.patch
new file mode 100644 (file)
index 0000000..0799d83
--- /dev/null
@@ -0,0 +1,39 @@
+From 42d8b74383b670412107c943efd2fec46aa04158 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Sat, 1 Jun 2013 16:32:46 -0500
+Subject: [PATCH 07/10] Revert "regulator: twl: Remove TWL6030_FIXED_RESOURCE"
+
+This reverts commit d1924519fe1dada0cfd9a228bf2ff1ea15840c84.
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/regulator/twl-regulator.c |   13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
+index fb6e67d..7ce7edf 100644
+--- a/drivers/regulator/twl-regulator.c
++++ b/drivers/regulator/twl-regulator.c
+@@ -933,6 +933,19 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \
+               }, \
+       }
++#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \
++static struct twlreg_info TWLRES_INFO_##label = { \
++      .base = offset, \
++      .desc = { \
++              .name = #label, \
++              .id = TWL6030_REG_##label, \
++              .ops = &twl6030_fixed_resource, \
++              .type = REGULATOR_VOLTAGE, \
++              .owner = THIS_MODULE, \
++              .enable_time = turnon_delay, \
++              }, \
++      }
++
+ #define TWL6025_ADJUSTABLE_SMPS(label, offset) \
+ static const struct twlreg_info TWLSMPS_INFO_##label = { \
+       .base = offset, \
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0008-Revert-regulator-twl-Remove-another-unused-variable-.patch b/src/patches/kernel/omap/panda/0008-Revert-regulator-twl-Remove-another-unused-variable-.patch
new file mode 100644 (file)
index 0000000..4abbd05
--- /dev/null
@@ -0,0 +1,34 @@
+From 48e4598f1b8e9dd486d551b76c5f5021d0dc946d Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Sat, 1 Jun 2013 16:32:48 -0500
+Subject: [PATCH 08/10] Revert "regulator: twl: Remove another unused variable
+ warning"
+
+This reverts commit 029dd3cefa46ecdd879f9b4e2df3bdf4371cc22c.
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/regulator/twl-regulator.c |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
+index 7ce7edf..124a2f2 100644
+--- a/drivers/regulator/twl-regulator.c
++++ b/drivers/regulator/twl-regulator.c
+@@ -633,6 +633,13 @@ static struct regulator_ops twl6030fixed_ops = {
+       .get_status     = twl6030reg_get_status,
+ };
++static struct regulator_ops twl6030_fixed_resource = {
++      .enable         = twl6030reg_enable,
++      .disable        = twl6030reg_disable,
++      .is_enabled     = twl6030reg_is_enabled,
++      .get_status     = twl6030reg_get_status,
++};
++
+ /*
+  * SMPS status and control
+  */
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0009-Revert-regulator-twl-Remove-references-to-the-twl403.patch b/src/patches/kernel/omap/panda/0009-Revert-regulator-twl-Remove-references-to-the-twl403.patch
new file mode 100644 (file)
index 0000000..27bc6ea
--- /dev/null
@@ -0,0 +1,28 @@
+From 76cc643690032d9789bbd17c9a3542cae4b0603e Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Sat, 1 Jun 2013 16:32:51 -0500
+Subject: [PATCH 09/10] Revert "regulator: twl: Remove references to the
+ twl4030 regulator"
+
+This reverts commit e76ab829cc2d8b6350a3f01fffb208df4d7d8c1b.
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/regulator/twl-regulator.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
+index 124a2f2..5a18317 100644
+--- a/drivers/regulator/twl-regulator.c
++++ b/drivers/regulator/twl-regulator.c
+@@ -1021,6 +1021,7 @@ TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0);
+ TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0);
+ TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0);
+ TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0);
++TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0);
+ TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34);
+ TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10);
+ TWL6025_ADJUSTABLE_SMPS(VIO, 0x16);
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0010-Revert-regulator-twl-Remove-references-to-32kHz-cloc.patch b/src/patches/kernel/omap/panda/0010-Revert-regulator-twl-Remove-references-to-32kHz-cloc.patch
new file mode 100644 (file)
index 0000000..ad18b29
--- /dev/null
@@ -0,0 +1,49 @@
+From ffdb3fad79cf70dcc943764f075215d6525435be Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Sat, 1 Jun 2013 16:32:54 -0500
+Subject: [PATCH 10/10] Revert "regulator: twl: Remove references to 32kHz
+ clock from DT bindings"
+
+This reverts commit 0e8e5c34cf1a8beaaf0a6a05c053592693bf8cb4.
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ Documentation/devicetree/bindings/regulator/twl-regulator.txt |    1 +
+ drivers/regulator/twl-regulator.c                             |    2 ++
+ 2 files changed, 3 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/regulator/twl-regulator.txt b/Documentation/devicetree/bindings/regulator/twl-regulator.txt
+index 658749b..0c3395d 100644
+--- a/Documentation/devicetree/bindings/regulator/twl-regulator.txt
++++ b/Documentation/devicetree/bindings/regulator/twl-regulator.txt
+@@ -15,6 +15,7 @@ For twl6030 regulators/LDOs
+   - "ti,twl6030-vusb" for VUSB LDO
+   - "ti,twl6030-v1v8" for V1V8 LDO
+   - "ti,twl6030-v2v1" for V2V1 LDO
++  - "ti,twl6030-clk32kg" for CLK32KG RESOURCE
+   - "ti,twl6030-vdd1" for VDD1 SMPS
+   - "ti,twl6030-vdd2" for VDD2 SMPS
+   - "ti,twl6030-vdd3" for VDD3 SMPS
+diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
+index 5a18317..40f27bb 100644
+--- a/drivers/regulator/twl-regulator.c
++++ b/drivers/regulator/twl-regulator.c
+@@ -1054,6 +1054,7 @@ static u8 twl_get_smps_mult(void)
+ #define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label)
+ #define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label)
+ #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
++#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label)
+ #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
+ static const struct of_device_id twl_of_match[] = {
+@@ -1101,6 +1102,7 @@ static const struct of_device_id twl_of_match[] = {
+       TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB),
+       TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8),
+       TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1),
++      TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG),
+       TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3),
+       TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4),
+       TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO),
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/panda/0011-panda-spidev-setup-pinmux.patch b/src/patches/kernel/omap/panda/0011-panda-spidev-setup-pinmux.patch
new file mode 100644 (file)
index 0000000..da9fcda
--- /dev/null
@@ -0,0 +1,50 @@
+From 9f5066a898b77f2fe2b1f0946bb6afebe3d08f6d Mon Sep 17 00:00:00 2001
+From: Yann <yann.wanwanscappel@free.fr>
+Date: Sat, 8 Jun 2013 13:06:37 -0500
+Subject: [PATCH 7/7] panda: spidev: setup pinmux
+
+It works fine on my board, I've been able to perform data transfers using the spidev_test program provided in kernel documentation
+(shortcut between SIMO and SOMI to perform an hardware loopback). I also checked that CS0 and CS1 and CLK are properly driven using my scope.
+
+The clock is strangely configured as input, but it is also the case for omap3 beagle board, so I guess this is fine.
+
+Signed-off-by: Yann <yann.wanwanscappel@free.fr>
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/mach-omap2/board-omap4panda.c |   13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
+index 3563f86..10bb576 100644
+--- a/arch/arm/mach-omap2/board-omap4panda.c
++++ b/arch/arm/mach-omap2/board-omap4panda.c
+@@ -103,6 +103,16 @@ static struct platform_device leds_gpio = {
+       },
+ };
++static void __init omap4_panda_config_mcspi1_mux(void)
++{
++      /* NOTE: Clock pins need to be in input mode */
++      omap_mux_init_signal("mcspi1_clk", OMAP_PIN_INPUT);
++      omap_mux_init_signal("mcspi1_simo", OMAP_PIN_OUTPUT);
++      omap_mux_init_signal("mcspi1_somi", OMAP_PIN_INPUT_PULLUP);
++      omap_mux_init_signal("mcspi1_cs0", OMAP_PIN_OUTPUT);
++      omap_mux_init_signal("mcspi1_cs1", OMAP_PIN_OUTPUT);
++}
++
+ static struct spi_board_info panda_mcspi_board_info[] = {
+       /* spi 1.0 */
+       {
+@@ -472,7 +482,8 @@ static void __init omap4_panda_init(void)
+       omap4_ehci_init();
+       if (!strcmp(expboard_name, "spidev")) {
+       #if IS_ENABLED(CONFIG_SPI_SPIDEV)
+-              pr_info("Panda expansionboard: spidev: enabling spi3/spi4\n");
++              pr_info("Panda expansionboard: spidev: enabling spi1.0 and spi1.1\n");
++              omap4_panda_config_mcspi1_mux();
+               spi_register_board_info(panda_mcspi_board_info, ARRAY_SIZE(panda_mcspi_board_info));
+       #endif
+       }
+-- 
+1.7.10.4
+
diff --git a/src/patches/kernel/omap/sakoman/0001-OMAP-DSS2-add-bootarg-for-selecting-svideo.patch b/src/patches/kernel/omap/sakoman/0001-OMAP-DSS2-add-bootarg-for-selecting-svideo.patch
new file mode 100644 (file)
index 0000000..8e8a08e
--- /dev/null
@@ -0,0 +1,78 @@
+From 6bce72b21600d9f52ae60d5bf80d00152eb75b50 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Tue, 19 Jan 2010 21:19:15 -0800
+Subject: [PATCH 1/2] OMAP: DSS2: add bootarg for selecting svideo
+
+ OMAP: DSS2: add bootarg for selecting svideo or composite for tv output
+ also add pal-16 and ntsc-16 omapfb.mode settings for 16bpp
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/video/omap2/dss/venc.c           |   22 ++++++++++++++++++++++
+ drivers/video/omap2/omapfb/omapfb-main.c |   10 +++++++++-
+ 2 files changed, 31 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
+index 56efa3b..d46f7f8 100644
+--- a/drivers/video/omap2/dss/venc.c
++++ b/drivers/video/omap2/dss/venc.c
+@@ -86,6 +86,11 @@
+ #define VENC_OUTPUT_TEST                      0xC8
+ #define VENC_DAC_B__DAC_C                     0xC8
++static char *tv_connection;
++
++module_param_named(tvcable, tv_connection, charp, 0);
++MODULE_PARM_DESC(tvcable, "TV connection type (svideo, composite)");
++
+ struct venc_config {
+       u32 f_control;
+       u32 vidout_ctrl;
+@@ -465,6 +470,23 @@ static int venc_power_on(struct omap_dss_device *dssdev)
+       if (r)
+               goto err2;
++      /* Allow the TV output to be overriden */
++      if (tv_connection) {
++              if (strcmp(tv_connection, "svideo") == 0) {
++                      printk(KERN_INFO
++                              "omapdss: tv output is svideo.\n");
++                      dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
++              } else if (strcmp(tv_connection, "composite") == 0) {
++                      printk(KERN_INFO
++                              "omapdss: tv output is composite.\n");
++                      dssdev->phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
++              } else {
++                      printk(KERN_INFO
++                              "omapdss: unsupported output type'%s'.\n",
++                              tv_connection);
++              }
++      }
++
+       return 0;
+ err2:
+diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
+index bc225e4..34d6679 100644
+--- a/drivers/video/omap2/omapfb/omapfb-main.c
++++ b/drivers/video/omap2/omapfb/omapfb-main.c
+@@ -2032,7 +2032,15 @@ static int omapfb_mode_to_timings(const char *mode_str,
+       int r;
+ #ifdef CONFIG_OMAP2_DSS_VENC
+-      if (strcmp(mode_str, "pal") == 0) {
++      if (strcmp(mode_str, "pal-16") == 0) {
++              *timings = omap_dss_pal_timings;
++              *bpp = 16;
++              return 0;
++      } else if (strcmp(mode_str, "ntsc-16") == 0) {
++              *timings = omap_dss_ntsc_timings;
++              *bpp = 16;
++              return 0;
++      } else if (strcmp(mode_str, "pal") == 0) {
+               *timings = omap_dss_pal_timings;
+               *bpp = 24;
+               return 0;
+-- 
+1.7.7.6
+
diff --git a/src/patches/kernel/omap/sakoman/0002-video-add-timings-for-hd720.patch b/src/patches/kernel/omap/sakoman/0002-video-add-timings-for-hd720.patch
new file mode 100644 (file)
index 0000000..1b936f5
--- /dev/null
@@ -0,0 +1,28 @@
+From 747de06d5cc69b2407684ba0455fff5c1d6af797 Mon Sep 17 00:00:00 2001
+From: Steve Sakoman <steve@sakoman.com>
+Date: Sat, 19 Dec 2009 06:52:43 -0800
+Subject: [PATCH 2/2] video: add timings for hd720
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ drivers/video/modedb.c |    4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
+index a9a907c..5b686de 100644
+--- a/drivers/video/modedb.c
++++ b/drivers/video/modedb.c
+@@ -103,6 +103,10 @@ static const struct fb_videomode modedb[] = {
+       { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0,
+               FB_VMODE_NONINTERLACED },
++      /* 1280x720 @ 60 Hz, 45 kHz hsync, CEA 681-E Format 4 */
++      { "hd720", 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5, 0,
++              FB_VMODE_NONINTERLACED },
++
+       /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */
+       { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0,
+               FB_VMODE_INTERLACED },
+-- 
+1.7.7.6
+
diff --git a/src/patches/kernel/omap/sgx/0001-arm-Export-cache-flush-management-symbols-when-MULTI.patch b/src/patches/kernel/omap/sgx/0001-arm-Export-cache-flush-management-symbols-when-MULTI.patch
new file mode 100644 (file)
index 0000000..1ca1e70
--- /dev/null
@@ -0,0 +1,34 @@
+From 29885f2f3d700341d322274db6ad085e601c0994 Mon Sep 17 00:00:00 2001
+From: Pantelis Antoniou <panto@antoniou-consulting.com>
+Date: Fri, 4 Jan 2013 00:32:33 +0200
+Subject: [PATCH 3/3] arm: Export cache flush management symbols when
+ !MULTI_CACHE
+
+When compiling a kernel without CONFIG_MULTI_CACHE enabled the
+dma access functions end up not being exported. Fix it.
+
+Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
+---
+ arch/arm/kernel/setup.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
+index da1d1aa..dcb678c 100644
+--- a/arch/arm/kernel/setup.c
++++ b/arch/arm/kernel/setup.c
+@@ -923,3 +923,12 @@ const struct seq_operations cpuinfo_op = {
+       .stop   = c_stop,
+       .show   = c_show
+ };
++
++/* export the cache management functions */
++#ifndef MULTI_CACHE
++
++EXPORT_SYMBOL(__glue(_CACHE,_dma_map_area));
++EXPORT_SYMBOL(__glue(_CACHE,_dma_unmap_area));
++EXPORT_SYMBOL(__glue(_CACHE,_dma_flush_range));
++
++#endif
+-- 
+1.7.10.4
+
diff --git a/src/patches/linux-3.10.25-imq.patch b/src/patches/linux-3.10.25-imq.patch
deleted file mode 100644 (file)
index cb4a2d4..0000000
+++ /dev/null
@@ -1,6800 +0,0 @@
-diff -ruN linux-3.10.27/drivers/net/imq.c linux-3.10.27-imq/drivers/net/imq.c
---- linux-3.10.27/drivers/net/imq.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.10.27-imq/drivers/net/imq.c        2014-01-18 10:19:59.342342913 +0100
-@@ -0,0 +1,1001 @@
-+/*
-+ *             Pseudo-driver for the intermediate queue device.
-+ *
-+ *             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.
-+ *
-+ * Authors:    Patrick McHardy, <kaber@trash.net>
-+ *
-+ *            The first version was written by Martin Devera, <devik@cdi.cz>
-+ *
-+ * Credits:    Jan Rafaj <imq2t@cedric.vabo.cz>
-+ *              - Update patch to 2.4.21
-+ *             Sebastian Strollo <sstrollo@nortelnetworks.com>
-+ *              - Fix "Dead-loop on netdevice imq"-issue
-+ *             Marcel Sebek <sebek64@post.cz>
-+ *              - Update to 2.6.2-rc1
-+ *
-+ *           After some time of inactivity there is a group taking care
-+ *           of IMQ again: http://www.linuximq.net
-+ *
-+ *
-+ *           2004/06/30 - New version of IMQ patch to kernels <=2.6.7
-+ *             including the following changes:
-+ *
-+ *           - Correction of ipv6 support "+"s issue (Hasso Tepper)
-+ *           - Correction of imq_init_devs() issue that resulted in
-+ *           kernel OOPS unloading IMQ as module (Norbert Buchmuller)
-+ *           - Addition of functionality to choose number of IMQ devices
-+ *           during kernel config (Andre Correa)
-+ *           - Addition of functionality to choose how IMQ hooks on
-+ *           PRE and POSTROUTING (after or before NAT) (Andre Correa)
-+ *           - Cosmetic corrections (Norbert Buchmuller) (Andre Correa)
-+ *
-+ *
-+ *             2005/12/16 - IMQ versions between 2.6.7 and 2.6.13 were
-+ *             released with almost no problems. 2.6.14-x was released
-+ *             with some important changes: nfcache was removed; After
-+ *             some weeks of trouble we figured out that some IMQ fields
-+ *             in skb were missing in skbuff.c - skb_clone and copy_skb_header.
-+ *             These functions are correctly patched by this new patch version.
-+ *
-+ *             Thanks for all who helped to figure out all the problems with
-+ *             2.6.14.x: Patrick McHardy, Rune Kock, VeNoMouS, Max CtRiX,
-+ *             Kevin Shanahan, Richard Lucassen, Valery Dachev (hopefully
-+ *             I didn't forget anybody). I apologize again for my lack of time.
-+ *
-+ *
-+ *             2008/06/17 - 2.6.25 - Changed imq.c to use qdisc_run() instead
-+ *             of qdisc_restart() and moved qdisc_run() to tasklet to avoid
-+ *             recursive locking. New initialization routines to fix 'rmmod' not
-+ *             working anymore. Used code from ifb.c. (Jussi Kivilinna)
-+ *
-+ *             2008/08/06 - 2.6.26 - (JK)
-+ *              - Replaced tasklet with 'netif_schedule()'.
-+ *              - Cleaned up and added comments for imq_nf_queue().
-+ *
-+ *             2009/04/12
-+ *              - Add skb_save_cb/skb_restore_cb helper functions for backuping
-+ *                control buffer. This is needed because qdisc-layer on kernels
-+ *                2.6.27 and newer overwrite control buffer. (Jussi Kivilinna)
-+ *              - Add better locking for IMQ device. Hopefully this will solve
-+ *                SMP issues. (Jussi Kivilinna)
-+ *              - Port to 2.6.27
-+ *              - Port to 2.6.28
-+ *              - Port to 2.6.29 + fix rmmod not working
-+ *
-+ *             2009/04/20 - (Jussi Kivilinna)
-+ *              - Use netdevice feature flags to avoid extra packet handling
-+ *                by core networking layer and possibly increase performance.
-+ *
-+ *             2009/09/26 - (Jussi Kivilinna)
-+ *              - Add imq_nf_reinject_lockless to fix deadlock with
-+ *                imq_nf_queue/imq_nf_reinject.
-+ *
-+ *             2009/12/08 - (Jussi Kivilinna)
-+ *              - Port to 2.6.32
-+ *              - Add check for skb->nf_queue_entry==NULL in imq_dev_xmit()
-+ *              - Also add better error checking for skb->nf_queue_entry usage
-+ *
-+ *             2010/02/25 - (Jussi Kivilinna)
-+ *              - Port to 2.6.33
-+ *
-+ *             2010/08/15 - (Jussi Kivilinna)
-+ *              - Port to 2.6.35
-+ *              - Simplify hook registration by using nf_register_hooks.
-+ *              - nf_reinject doesn't need spinlock around it, therefore remove
-+ *                imq_nf_reinject function. Other nf_reinject users protect
-+ *                their own data with spinlock. With IMQ however all data is
-+ *                needed is stored per skbuff, so no locking is needed.
-+ *              - Changed IMQ to use 'separate' NF_IMQ_QUEUE instead of
-+ *                NF_QUEUE, this allows working coexistance of IMQ and other
-+ *                NF_QUEUE users.
-+ *              - Make IMQ multi-queue. Number of IMQ device queues can be
-+ *                increased with 'numqueues' module parameters. Default number
-+ *                of queues is 1, in other words by default IMQ works as
-+ *                single-queue device. Multi-queue selection is based on
-+ *                IFB multi-queue patch by Changli Gao <xiaosuo@gmail.com>.
-+ *
-+ *             2011/03/18 - (Jussi Kivilinna)
-+ *              - Port to 2.6.38
-+ *
-+ *             2011/07/12 - (syoder89@gmail.com)
-+ *              - Crash fix that happens when the receiving interface has more
-+ *                than one queue (add missing skb_set_queue_mapping in
-+ *                imq_select_queue).
-+ *
-+ *             2011/07/26 - (Jussi Kivilinna)
-+ *              - Add queue mapping checks for packets exiting IMQ.
-+ *              - Port to 3.0
-+ *
-+ *             2011/08/16 - (Jussi Kivilinna)
-+ *              - Clear IFF_TX_SKB_SHARING flag that was added for linux 3.0.2
-+ *
-+ *             2011/11/03 - Germano Michel <germanomichel@gmail.com>
-+ *              - Fix IMQ for net namespaces
-+ *
-+ *             2011/11/04 - Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
-+ *              - Port to 3.1
-+ *              - Clean-up, move 'get imq device pointer by imqX name' to
-+ *                separate function from imq_nf_queue().
-+ *
-+ *             2012/01/05 - Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
-+ *              - Port to 3.2
-+ *
-+ *             2012/03/19 - Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
-+ *              - Port to 3.3
-+ *
-+ *             2012/12/12 - Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
-+ *              - Port to 3.7
-+ *              - Fix checkpatch.pl warnings
-+ *
-+ *             2013/09/10 - Jussi Kivilinna <jussi.kivilinna@iki.fi>
-+ *              - Fixed GSO handling for 3.10, see imq_nf_queue() for comments.
-+ *              - Don't copy skb->cb_next when copying or cloning skbuffs.
-+ *
-+ *           Also, many thanks to pablo Sebastian Greco for making the initial
-+ *           patch and to those who helped the testing.
-+ *
-+ *             More info at: http://www.linuximq.net/ (Andre Correa)
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/moduleparam.h>
-+#include <linux/list.h>
-+#include <linux/skbuff.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/if_arp.h>
-+#include <linux/netfilter.h>
-+#include <linux/netfilter_ipv4.h>
-+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+      #include <linux/netfilter_ipv6.h>
-+#endif
-+#include <linux/imq.h>
-+#include <net/pkt_sched.h>
-+#include <net/netfilter/nf_queue.h>
-+#include <net/sock.h>
-+#include <linux/ip.h>
-+#include <linux/ipv6.h>
-+#include <linux/if_vlan.h>
-+#include <linux/if_pppox.h>
-+#include <net/ip.h>
-+#include <net/ipv6.h>
-+
-+static int imq_nf_queue(struct nf_queue_entry *entry, unsigned queue_num);
-+
-+static nf_hookfn imq_nf_hook;
-+
-+static struct nf_hook_ops imq_ops[] = {
-+      {
-+      /* imq_ingress_ipv4 */
-+              .hook           = imq_nf_hook,
-+              .owner          = THIS_MODULE,
-+              .pf             = PF_INET,
-+              .hooknum        = NF_INET_PRE_ROUTING,
-+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
-+              .priority       = NF_IP_PRI_MANGLE + 1,
-+#else
-+              .priority       = NF_IP_PRI_NAT_DST + 1,
-+#endif
-+      },
-+      {
-+      /* imq_egress_ipv4 */
-+              .hook           = imq_nf_hook,
-+              .owner          = THIS_MODULE,
-+              .pf             = PF_INET,
-+              .hooknum        = NF_INET_POST_ROUTING,
-+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
-+              .priority       = NF_IP_PRI_LAST,
-+#else
-+              .priority       = NF_IP_PRI_NAT_SRC - 1,
-+#endif
-+      },
-+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+      {
-+      /* imq_ingress_ipv6 */
-+              .hook           = imq_nf_hook,
-+              .owner          = THIS_MODULE,
-+              .pf             = PF_INET6,
-+              .hooknum        = NF_INET_PRE_ROUTING,
-+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
-+              .priority       = NF_IP6_PRI_MANGLE + 1,
-+#else
-+              .priority       = NF_IP6_PRI_NAT_DST + 1,
-+#endif
-+      },
-+      {
-+      /* imq_egress_ipv6 */
-+              .hook           = imq_nf_hook,
-+              .owner          = THIS_MODULE,
-+              .pf             = PF_INET6,
-+              .hooknum        = NF_INET_POST_ROUTING,
-+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
-+              .priority       = NF_IP6_PRI_LAST,
-+#else
-+              .priority       = NF_IP6_PRI_NAT_SRC - 1,
-+#endif
-+      },
-+#endif
-+};
-+
-+#if defined(CONFIG_IMQ_NUM_DEVS)
-+static int numdevs = CONFIG_IMQ_NUM_DEVS;
-+#else
-+static int numdevs = IMQ_MAX_DEVS;
-+#endif
-+
-+static struct net_device *imq_devs_cache[IMQ_MAX_DEVS];
-+
-+#define IMQ_MAX_QUEUES 32
-+static int numqueues = 1;
-+static u32 imq_hashrnd;
-+
-+static inline __be16 pppoe_proto(const struct sk_buff *skb)
-+{
-+      return *((__be16 *)(skb_mac_header(skb) + ETH_HLEN +
-+                      sizeof(struct pppoe_hdr)));
-+}
-+
-+static u16 imq_hash(struct net_device *dev, struct sk_buff *skb)
-+{
-+      unsigned int pull_len;
-+      u16 protocol = skb->protocol;
-+      u32 addr1, addr2;
-+      u32 hash, ihl = 0;
-+      union {
-+              u16 in16[2];
-+              u32 in32;
-+      } ports;
-+      u8 ip_proto;
-+
-+      pull_len = 0;
-+
-+recheck:
-+      switch (protocol) {
-+      case htons(ETH_P_8021Q): {
-+              if (unlikely(skb_pull(skb, VLAN_HLEN) == NULL))
-+                      goto other;
-+
-+              pull_len += VLAN_HLEN;
-+              skb->network_header += VLAN_HLEN;
-+
-+              protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-+              goto recheck;
-+      }
-+
-+      case htons(ETH_P_PPP_SES): {
-+              if (unlikely(skb_pull(skb, PPPOE_SES_HLEN) == NULL))
-+                      goto other;
-+
-+              pull_len += PPPOE_SES_HLEN;
-+              skb->network_header += PPPOE_SES_HLEN;
-+
-+              protocol = pppoe_proto(skb);
-+              goto recheck;
-+      }
-+
-+      case htons(ETH_P_IP): {
-+              const struct iphdr *iph = ip_hdr(skb);
-+
-+              if (unlikely(!pskb_may_pull(skb, sizeof(struct iphdr))))
-+                      goto other;
-+
-+              addr1 = iph->daddr;
-+              addr2 = iph->saddr;
-+
-+              ip_proto = !(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) ?
-+                               iph->protocol : 0;
-+              ihl = ip_hdrlen(skb);
-+
-+              break;
-+      }
-+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-+      case htons(ETH_P_IPV6): {
-+              const struct ipv6hdr *iph = ipv6_hdr(skb);
-+              __be16 fo = 0;
-+
-+              if (unlikely(!pskb_may_pull(skb, sizeof(struct ipv6hdr))))
-+                      goto other;
-+
-+              addr1 = iph->daddr.s6_addr32[3];
-+              addr2 = iph->saddr.s6_addr32[3];
-+              ihl = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &ip_proto,
-+                                     &fo);
-+              if (unlikely(ihl < 0))
-+                      goto other;
-+
-+              break;
-+      }
-+#endif
-+      default:
-+other:
-+              if (pull_len != 0) {
-+                      skb_push(skb, pull_len);
-+                      skb->network_header -= pull_len;
-+              }
-+
-+              return (u16)(ntohs(protocol) % dev->real_num_tx_queues);
-+      }
-+
-+      if (addr1 > addr2)
-+              swap(addr1, addr2);
-+
-+      switch (ip_proto) {
-+      case IPPROTO_TCP:
-+      case IPPROTO_UDP:
-+      case IPPROTO_DCCP:
-+      case IPPROTO_ESP:
-+      case IPPROTO_AH:
-+      case IPPROTO_SCTP:
-+      case IPPROTO_UDPLITE: {
-+              if (likely(skb_copy_bits(skb, ihl, &ports.in32, 4) >= 0)) {
-+                      if (ports.in16[0] > ports.in16[1])
-+                              swap(ports.in16[0], ports.in16[1]);
-+                      break;
-+              }
-+              /* fall-through */
-+      }
-+      default:
-+              ports.in32 = 0;
-+              break;
-+      }
-+
-+      if (pull_len != 0) {
-+              skb_push(skb, pull_len);
-+              skb->network_header -= pull_len;
-+      }
-+
-+      hash = jhash_3words(addr1, addr2, ports.in32, imq_hashrnd ^ ip_proto);
-+
-+      return (u16)(((u64)hash * dev->real_num_tx_queues) >> 32);
-+}
-+
-+static inline bool sk_tx_queue_recorded(struct sock *sk)
-+{
-+      return (sk_tx_queue_get(sk) >= 0);
-+}
-+
-+static struct netdev_queue *imq_select_queue(struct net_device *dev,
-+                                              struct sk_buff *skb)
-+{
-+      u16 queue_index = 0;
-+      u32 hash;
-+
-+      if (likely(dev->real_num_tx_queues == 1))
-+              goto out;
-+
-+      /* IMQ can be receiving ingress or engress packets. */
-+
-+      /* Check first for if rx_queue is set */
-+      if (skb_rx_queue_recorded(skb)) {
-+              queue_index = skb_get_rx_queue(skb);
-+              goto out;
-+      }
-+
-+      /* Check if socket has tx_queue set */
-+      if (sk_tx_queue_recorded(skb->sk)) {
-+              queue_index = sk_tx_queue_get(skb->sk);
-+              goto out;
-+      }
-+
-+      /* Try use socket hash */
-+      if (skb->sk && skb->sk->sk_hash) {
-+              hash = skb->sk->sk_hash;
-+              queue_index =
-+                      (u16)(((u64)hash * dev->real_num_tx_queues) >> 32);
-+              goto out;
-+      }
-+
-+      /* Generate hash from packet data */
-+      queue_index = imq_hash(dev, skb);
-+
-+out:
-+      if (unlikely(queue_index >= dev->real_num_tx_queues))
-+              queue_index = (u16)((u32)queue_index % dev->real_num_tx_queues);
-+
-+      skb_set_queue_mapping(skb, queue_index);
-+      return netdev_get_tx_queue(dev, queue_index);
-+}
-+
-+static struct net_device_stats *imq_get_stats(struct net_device *dev)
-+{
-+      return &dev->stats;
-+}
-+
-+/* called for packets kfree'd in qdiscs at places other than enqueue */
-+static void imq_skb_destructor(struct sk_buff *skb)
-+{
-+      struct nf_queue_entry *entry = skb->nf_queue_entry;
-+
-+      skb->nf_queue_entry = NULL;
-+
-+      if (entry) {
-+              nf_queue_entry_release_refs(entry);
-+              kfree(entry);
-+      }
-+
-+      skb_restore_cb(skb); /* kfree backup */
-+}
-+
-+static void imq_done_check_queue_mapping(struct sk_buff *skb,
-+                                       struct net_device *dev)
-+{
-+      unsigned int queue_index;
-+
-+      /* Don't let queue_mapping be left too large after exiting IMQ */
-+      if (likely(skb->dev != dev && skb->dev != NULL)) {
-+              queue_index = skb_get_queue_mapping(skb);
-+              if (unlikely(queue_index >= skb->dev->real_num_tx_queues)) {
-+                      queue_index = (u16)((u32)queue_index %
-+                                              skb->dev->real_num_tx_queues);
-+                      skb_set_queue_mapping(skb, queue_index);
-+              }
-+      } else {
-+              /* skb->dev was IMQ device itself or NULL, be on safe side and
-+               * just clear queue mapping.
-+               */
-+              skb_set_queue_mapping(skb, 0);
-+      }
-+}
-+
-+static netdev_tx_t imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+      struct nf_queue_entry *entry = skb->nf_queue_entry;
-+
-+      skb->nf_queue_entry = NULL;
-+      dev->trans_start = jiffies;
-+
-+      dev->stats.tx_bytes += skb->len;
-+      dev->stats.tx_packets++;
-+
-+      if (unlikely(entry == NULL)) {
-+              /* We don't know what is going on here.. packet is queued for
-+               * imq device, but (probably) not by us.
-+               *
-+               * If this packet was not send here by imq_nf_queue(), then
-+               * skb_save_cb() was not used and skb_free() should not show:
-+               *   WARNING: IMQ: kfree_skb: skb->cb_next:..
-+               * and/or
-+               *   WARNING: IMQ: kfree_skb: skb->nf_queue_entry...
-+               *
-+               * However if this message is shown, then IMQ is somehow broken
-+               * and you should report this to linuximq.net.
-+               */
-+
-+              /* imq_dev_xmit is black hole that eats all packets, report that
-+               * we eat this packet happily and increase dropped counters.
-+               */
-+
-+              dev->stats.tx_dropped++;
-+              dev_kfree_skb(skb);
-+
-+              return NETDEV_TX_OK;
-+      }
-+
-+      skb_restore_cb(skb); /* restore skb->cb */
-+
-+      skb->imq_flags = 0;
-+      skb->destructor = NULL;
-+
-+      imq_done_check_queue_mapping(skb, dev);
-+
-+      nf_reinject(entry, NF_ACCEPT);
-+
-+      return NETDEV_TX_OK;
-+}
-+
-+static struct net_device *get_imq_device_by_index(int index)
-+{
-+      struct net_device *dev = NULL;
-+      struct net *net;
-+      char buf[8];
-+
-+      /* get device by name and cache result */
-+      snprintf(buf, sizeof(buf), "imq%d", index);
-+
-+      /* Search device from all namespaces. */
-+      for_each_net(net) {
-+              dev = dev_get_by_name(net, buf);
-+              if (dev)
-+                      break;
-+      }
-+
-+      if (WARN_ON_ONCE(dev == NULL)) {
-+              /* IMQ device not found. Exotic config? */
-+              return ERR_PTR(-ENODEV);
-+      }
-+
-+      imq_devs_cache[index] = dev;
-+      dev_put(dev);
-+
-+      return dev;
-+}
-+
-+static struct nf_queue_entry *nf_queue_entry_dup(struct nf_queue_entry *e)
-+{
-+      struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
-+      if (entry) {
-+              if (nf_queue_entry_get_refs(entry))
-+                      return entry;
-+              kfree(entry);
-+      }
-+      return NULL;
-+}
-+
-+#ifdef CONFIG_BRIDGE_NETFILTER
-+/* When called from bridge netfilter, skb->data must point to MAC header
-+ * before calling skb_gso_segment(). Else, original MAC header is lost
-+ * and segmented skbs will be sent to wrong destination.
-+ */
-+static void nf_bridge_adjust_skb_data(struct sk_buff *skb)
-+{
-+      if (skb->nf_bridge)
-+              __skb_push(skb, skb->network_header - skb->mac_header);
-+}
-+
-+static void nf_bridge_adjust_segmented_data(struct sk_buff *skb)
-+{
-+      if (skb->nf_bridge)
-+              __skb_pull(skb, skb->network_header - skb->mac_header);
-+}
-+#else
-+#define nf_bridge_adjust_skb_data(s) do {} while (0)
-+#define nf_bridge_adjust_segmented_data(s) do {} while (0)
-+#endif
-+
-+static void free_entry(struct nf_queue_entry *entry)
-+{
-+      nf_queue_entry_release_refs(entry);
-+      kfree(entry);
-+}
-+
-+static int __imq_nf_queue(struct nf_queue_entry *entry, struct net_device *dev);
-+
-+static int __imq_nf_queue_gso(struct nf_queue_entry *entry,
-+                            struct net_device *dev, struct sk_buff *skb)
-+{
-+      int ret = -ENOMEM;
-+      struct nf_queue_entry *entry_seg;
-+
-+      nf_bridge_adjust_segmented_data(skb);
-+
-+      if (skb->next == NULL) { /* last packet, no need to copy entry */
-+              struct sk_buff *gso_skb = entry->skb;
-+              entry->skb = skb;
-+              ret = __imq_nf_queue(entry, dev);
-+              if (ret)
-+                      entry->skb = gso_skb;
-+              return ret;
-+      }
-+
-+      skb->next = NULL;
-+
-+      entry_seg = nf_queue_entry_dup(entry);
-+      if (entry_seg) {
-+              entry_seg->skb = skb;
-+              ret = __imq_nf_queue(entry_seg, dev);
-+              if (ret)
-+                      free_entry(entry_seg);
-+      }
-+      return ret;
-+}
-+
-+static int imq_nf_queue(struct nf_queue_entry *entry, unsigned queue_num)
-+{
-+      struct sk_buff *skb, *segs;
-+      struct net_device *dev;
-+      unsigned int queued;
-+      int index, retval, err;
-+
-+      index = entry->skb->imq_flags & IMQ_F_IFMASK;
-+      if (unlikely(index > numdevs - 1)) {
-+              if (net_ratelimit())
-+                      pr_warn("IMQ: invalid device specified, highest is %u\n",
-+                              numdevs - 1);
-+              retval = -EINVAL;
-+              goto out_no_dev;
-+      }
-+
-+      /* check for imq device by index from cache */
-+      dev = imq_devs_cache[index];
-+      if (unlikely(!dev)) {
-+              dev = get_imq_device_by_index(index);
-+              if (IS_ERR(dev)) {
-+                      retval = PTR_ERR(dev);
-+                      goto out_no_dev;
-+              }
-+      }
-+
-+      if (unlikely(!(dev->flags & IFF_UP))) {
-+              entry->skb->imq_flags = 0;
-+              retval = -ECANCELED;
-+              goto out_no_dev;
-+      }
-+
-+      if (!skb_is_gso(entry->skb))
-+              return __imq_nf_queue(entry, dev);
-+
-+      /* Since 3.10.x, GSO handling moved here as result of upstream commit
-+       * a5fedd43d5f6c94c71053a66e4c3d2e35f1731a2 (netfilter: move
-+       * skb_gso_segment into nfnetlink_queue module).
-+       *
-+       * Following code replicates the gso handling from
-+       * 'net/netfilter/nfnetlink_queue_core.c':nfqnl_enqueue_packet().
-+       */
-+
-+      skb = entry->skb;
-+
-+      switch (entry->pf) {
-+      case NFPROTO_IPV4:
-+              skb->protocol = htons(ETH_P_IP);
-+              break;
-+      case NFPROTO_IPV6:
-+              skb->protocol = htons(ETH_P_IPV6);
-+              break;
-+      }
-+
-+      nf_bridge_adjust_skb_data(skb);
-+      segs = skb_gso_segment(skb, 0);
-+      /* Does not use PTR_ERR to limit the number of error codes that can be
-+       * returned by nf_queue.  For instance, callers rely on -ECANCELED to
-+       * mean 'ignore this hook'.
-+       */
-+      err = -ENOBUFS;
-+      if (IS_ERR(segs))
-+              goto out_err;
-+      queued = 0;
-+      err = 0;
-+      do {
-+              struct sk_buff *nskb = segs->next;
-+              if (nskb && nskb->next)
-+                      nskb->cb_next = NULL;
-+              if (err == 0)
-+                      err = __imq_nf_queue_gso(entry, dev, segs);
-+              if (err == 0)
-+                      queued++;
-+              else
-+                      kfree_skb(segs);
-+              segs = nskb;
-+      } while (segs);
-+
-+      if (queued) {
-+              if (err) /* some segments are already queued */
-+                      free_entry(entry);
-+              kfree_skb(skb);
-+              return 0;
-+      }
-+
-+out_err:
-+      nf_bridge_adjust_segmented_data(skb);
-+      retval = err;
-+out_no_dev:
-+      return retval;
-+}
-+
-+static int __imq_nf_queue(struct nf_queue_entry *entry, struct net_device *dev)
-+{
-+      struct sk_buff *skb_orig, *skb, *skb_shared;
-+      struct Qdisc *q;
-+      struct netdev_queue *txq;
-+      spinlock_t *root_lock;
-+      int users;
-+      int retval = -EINVAL;
-+      unsigned int orig_queue_index;
-+
-+      dev->last_rx = jiffies;
-+
-+      skb = entry->skb;
-+      skb_orig = NULL;
-+
-+      /* skb has owner? => make clone */
-+      if (unlikely(skb->destructor)) {
-+              skb_orig = skb;
-+              skb = skb_clone(skb, GFP_ATOMIC);
-+              if (unlikely(!skb)) {
-+                      retval = -ENOMEM;
-+                      goto out;
-+              }
-+              skb->cb_next = NULL;
-+              entry->skb = skb;
-+      }
-+
-+      skb->nf_queue_entry = entry;
-+
-+      dev->stats.rx_bytes += skb->len;
-+      dev->stats.rx_packets++;
-+
-+      if (!skb->dev) {
-+              /* skb->dev == NULL causes problems, try the find cause. */
-+              if (net_ratelimit()) {
-+                      dev_warn(&dev->dev,
-+                               "received packet with skb->dev == NULL\n");
-+                      dump_stack();
-+              }
-+
-+              skb->dev = dev;
-+      }
-+
-+      /* Disables softirqs for lock below */
-+      rcu_read_lock_bh();
-+
-+      /* Multi-queue selection */
-+      orig_queue_index = skb_get_queue_mapping(skb);
-+      txq = imq_select_queue(dev, skb);
-+
-+      q = rcu_dereference(txq->qdisc);
-+      if (unlikely(!q->enqueue))
-+              goto packet_not_eaten_by_imq_dev;
-+
-+      root_lock = qdisc_lock(q);
-+      spin_lock(root_lock);
-+
-+      users = atomic_read(&skb->users);
-+
-+      skb_shared = skb_get(skb); /* increase reference count by one */
-+
-+      /* backup skb->cb, as qdisc layer will overwrite it */
-+      skb_save_cb(skb_shared);
-+      qdisc_enqueue_root(skb_shared, q); /* might kfree_skb */
-+
-+      if (likely(atomic_read(&skb_shared->users) == users + 1)) {
-+              kfree_skb(skb_shared); /* decrease reference count by one */
-+
-+              skb->destructor = &imq_skb_destructor;
-+
-+              /* cloned? */
-+              if (unlikely(skb_orig))
-+                      kfree_skb(skb_orig); /* free original */
-+
-+              spin_unlock(root_lock);
-+              rcu_read_unlock_bh();
-+
-+              /* schedule qdisc dequeue */
-+              __netif_schedule(q);
-+
-+              retval = 0;
-+              goto out;
-+      } else {
-+              skb_restore_cb(skb_shared); /* restore skb->cb */
-+              skb->nf_queue_entry = NULL;
-+              /*
-+               * qdisc dropped packet and decreased skb reference count of
-+               * skb, so we don't really want to and try refree as that would
-+               * actually destroy the skb.
-+               */
-+              spin_unlock(root_lock);
-+              goto packet_not_eaten_by_imq_dev;
-+      }
-+
-+packet_not_eaten_by_imq_dev:
-+      skb_set_queue_mapping(skb, orig_queue_index);
-+      rcu_read_unlock_bh();
-+
-+      /* cloned? restore original */
-+      if (unlikely(skb_orig)) {
-+              kfree_skb(skb);
-+              entry->skb = skb_orig;
-+      }
-+      retval = -1;
-+out:
-+      return retval;
-+}
-+
-+static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff *pskb,
-+                              const struct net_device *indev,
-+                              const struct net_device *outdev,
-+                              int (*okfn)(struct sk_buff *))
-+{
-+      return (pskb->imq_flags & IMQ_F_ENQUEUE) ? NF_IMQ_QUEUE : NF_ACCEPT;
-+}
-+
-+static int imq_close(struct net_device *dev)
-+{
-+      netif_stop_queue(dev);
-+      return 0;
-+}
-+
-+static int imq_open(struct net_device *dev)
-+{
-+      netif_start_queue(dev);
-+      return 0;
-+}
-+
-+static const struct net_device_ops imq_netdev_ops = {
-+      .ndo_open               = imq_open,
-+      .ndo_stop               = imq_close,
-+      .ndo_start_xmit         = imq_dev_xmit,
-+      .ndo_get_stats          = imq_get_stats,
-+};
-+
-+static void imq_setup(struct net_device *dev)
-+{
-+      dev->netdev_ops         = &imq_netdev_ops;
-+      dev->type               = ARPHRD_VOID;
-+      dev->mtu                = 16000; /* too small? */
-+      dev->tx_queue_len       = 11000; /* too big? */
-+      dev->flags              = IFF_NOARP;
-+      dev->features           = NETIF_F_SG | NETIF_F_FRAGLIST |
-+                                NETIF_F_GSO | NETIF_F_HW_CSUM |
-+                                NETIF_F_HIGHDMA;
-+      dev->priv_flags         &= ~(IFF_XMIT_DST_RELEASE |
-+                                   IFF_TX_SKB_SHARING);
-+}
-+
-+static int imq_validate(struct nlattr *tb[], struct nlattr *data[])
-+{
-+      int ret = 0;
-+
-+      if (tb[IFLA_ADDRESS]) {
-+              if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) {
-+                      ret = -EINVAL;
-+                      goto end;
-+              }
-+              if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) {
-+                      ret = -EADDRNOTAVAIL;
-+                      goto end;
-+              }
-+      }
-+      return 0;
-+end:
-+      pr_warn("IMQ: imq_validate failed (%d)\n", ret);
-+      return ret;
-+}
-+
-+static struct rtnl_link_ops imq_link_ops __read_mostly = {
-+      .kind           = "imq",
-+      .priv_size      = 0,
-+      .setup          = imq_setup,
-+      .validate       = imq_validate,
-+};
-+
-+static const struct nf_queue_handler imq_nfqh = {
-+      .outfn = imq_nf_queue,
-+};
-+
-+static int __init imq_init_hooks(void)
-+{
-+      int ret;
-+
-+      nf_register_queue_imq_handler(&imq_nfqh);
-+
-+      ret = nf_register_hooks(imq_ops, ARRAY_SIZE(imq_ops));
-+      if (ret < 0)
-+              nf_unregister_queue_imq_handler();
-+
-+      return ret;
-+}
-+
-+static int __init imq_init_one(int index)
-+{
-+      struct net_device *dev;
-+      int ret;
-+
-+      dev = alloc_netdev_mq(0, "imq%d", imq_setup, numqueues);
-+      if (!dev)
-+              return -ENOMEM;
-+
-+      ret = dev_alloc_name(dev, dev->name);
-+      if (ret < 0)
-+              goto fail;
-+
-+      dev->rtnl_link_ops = &imq_link_ops;
-+      ret = register_netdevice(dev);
-+      if (ret < 0)
-+              goto fail;
-+
-+      return 0;
-+fail:
-+      free_netdev(dev);
-+      return ret;
-+}
-+
-+static int __init imq_init_devs(void)
-+{
-+      int err, i;
-+
-+      if (numdevs < 1 || numdevs > IMQ_MAX_DEVS) {
-+              pr_err("IMQ: numdevs has to be betweed 1 and %u\n",
-+                     IMQ_MAX_DEVS);
-+              return -EINVAL;
-+      }
-+
-+      if (numqueues < 1 || numqueues > IMQ_MAX_QUEUES) {
-+              pr_err("IMQ: numqueues has to be betweed 1 and %u\n",
-+                     IMQ_MAX_QUEUES);
-+              return -EINVAL;
-+      }
-+
-+      get_random_bytes(&imq_hashrnd, sizeof(imq_hashrnd));
-+
-+      rtnl_lock();
-+      err = __rtnl_link_register(&imq_link_ops);
-+
-+      for (i = 0; i < numdevs && !err; i++)
-+              err = imq_init_one(i);
-+
-+      if (err) {
-+              __rtnl_link_unregister(&imq_link_ops);
-+              memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
-+      }
-+      rtnl_unlock();
-+
-+      return err;
-+}
-+
-+static int __init imq_init_module(void)
-+{
-+      int err;
-+
-+#if defined(CONFIG_IMQ_NUM_DEVS)
-+      BUILD_BUG_ON(CONFIG_IMQ_NUM_DEVS > 16);
-+      BUILD_BUG_ON(CONFIG_IMQ_NUM_DEVS < 2);
-+      BUILD_BUG_ON(CONFIG_IMQ_NUM_DEVS - 1 > IMQ_F_IFMASK);
-+#endif
-+
-+      err = imq_init_devs();
-+      if (err) {
-+              pr_err("IMQ: Error trying imq_init_devs(net)\n");
-+              return err;
-+      }
-+
-+      err = imq_init_hooks();
-+      if (err) {
-+              pr_err(KERN_ERR "IMQ: Error trying imq_init_hooks()\n");
-+              rtnl_link_unregister(&imq_link_ops);
-+              memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
-+              return err;
-+      }
-+
-+      pr_info("IMQ driver loaded successfully. (numdevs = %d, numqueues = %d)\n",
-+              numdevs, numqueues);
-+
-+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
-+      pr_info("\tHooking IMQ before NAT on PREROUTING.\n");
-+#else
-+      pr_info("\tHooking IMQ after NAT on PREROUTING.\n");
-+#endif
-+#if defined(CONFIG_IMQ_BEHAVIOR_AB) || defined(CONFIG_IMQ_BEHAVIOR_BB)
-+      pr_info("\tHooking IMQ before NAT on POSTROUTING.\n");
-+#else
-+      pr_info("\tHooking IMQ after NAT on POSTROUTING.\n");
-+#endif
-+
-+      return 0;
-+}
-+
-+static void __exit imq_unhook(void)
-+{
-+      nf_unregister_hooks(imq_ops, ARRAY_SIZE(imq_ops));
-+      nf_unregister_queue_imq_handler();
-+}
-+
-+static void __exit imq_cleanup_devs(void)
-+{
-+      rtnl_link_unregister(&imq_link_ops);
-+      memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
-+}
-+
-+static void __exit imq_exit_module(void)
-+{
-+      imq_unhook();
-+      imq_cleanup_devs();
-+      pr_info("IMQ driver unloaded successfully.\n");
-+}
-+
-+module_init(imq_init_module);
-+module_exit(imq_exit_module);
-+
-+module_param(numdevs, int, 0);
-+module_param(numqueues, int, 0);
-+MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will be created)");
-+MODULE_PARM_DESC(numqueues, "number of queues per IMQ device");
-+MODULE_AUTHOR("http://www.linuximq.net");
-+MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS_RTNL_LINK("imq");
-+
-diff -ruN linux-3.10.27/drivers/net/Kconfig linux-3.10.27-imq/drivers/net/Kconfig
---- linux-3.10.27/drivers/net/Kconfig  2014-01-16 00:29:14.000000000 +0100
-+++ linux-3.10.27-imq/drivers/net/Kconfig      2014-01-18 10:19:59.341342885 +0100
-@@ -207,6 +207,125 @@
-       depends on RIONET
-       default "128"
-+config IMQ
-+      tristate "IMQ (intermediate queueing device) support"
-+      depends on NETDEVICES && NETFILTER
-+      ---help---
-+        The IMQ device(s) is used as placeholder for QoS queueing
-+        disciplines. Every packet entering/leaving the IP stack can be
-+        directed through the IMQ device where it's enqueued/dequeued to the
-+        attached qdisc. This allows you to treat network devices as classes
-+        and distribute bandwidth among them. Iptables is used to specify
-+        through which IMQ device, if any, packets travel.
-+
-+        More information at: http://www.linuximq.net/
-+
-+        To compile this driver as a module, choose M here: the module
-+        will be called imq.  If unsure, say N.
-+
-+choice
-+      prompt "IMQ behavior (PRE/POSTROUTING)"
-+      depends on IMQ
-+      default IMQ_BEHAVIOR_AB
-+      help
-+        This setting defines how IMQ behaves in respect to its
-+        hooking in PREROUTING and POSTROUTING.
-+
-+        IMQ can work in any of the following ways:
-+
-+            PREROUTING   |      POSTROUTING
-+        -----------------|-------------------
-+        #1  After NAT    |      After NAT
-+        #2  After NAT    |      Before NAT
-+        #3  Before NAT   |      After NAT
-+        #4  Before NAT   |      Before NAT
-+
-+        The default behavior is to hook before NAT on PREROUTING
-+        and after NAT on POSTROUTING (#3).
-+
-+        This settings are specially usefull when trying to use IMQ
-+        to shape NATed clients.
-+
-+        More information can be found at: www.linuximq.net
-+
-+        If not sure leave the default settings alone.
-+
-+config IMQ_BEHAVIOR_AA
-+      bool "IMQ AA"
-+      help
-+        This setting defines how IMQ behaves in respect to its
-+        hooking in PREROUTING and POSTROUTING.
-+
-+        Choosing this option will make IMQ hook like this:
-+
-+        PREROUTING:   After NAT
-+        POSTROUTING:  After NAT
-+
-+        More information can be found at: www.linuximq.net
-+
-+        If not sure leave the default settings alone.
-+
-+config IMQ_BEHAVIOR_AB
-+      bool "IMQ AB"
-+      help
-+        This setting defines how IMQ behaves in respect to its
-+        hooking in PREROUTING and POSTROUTING.
-+
-+        Choosing this option will make IMQ hook like this:
-+
-+        PREROUTING:   After NAT
-+        POSTROUTING:  Before NAT
-+
-+        More information can be found at: www.linuximq.net
-+
-+        If not sure leave the default settings alone.
-+
-+config IMQ_BEHAVIOR_BA
-+      bool "IMQ BA"
-+      help
-+        This setting defines how IMQ behaves in respect to its
-+        hooking in PREROUTING and POSTROUTING.
-+
-+        Choosing this option will make IMQ hook like this:
-+
-+        PREROUTING:   Before NAT
-+        POSTROUTING:  After NAT
-+
-+        More information can be found at: www.linuximq.net
-+
-+        If not sure leave the default settings alone.
-+
-+config IMQ_BEHAVIOR_BB
-+      bool "IMQ BB"
-+      help
-+        This setting defines how IMQ behaves in respect to its
-+        hooking in PREROUTING and POSTROUTING.
-+
-+        Choosing this option will make IMQ hook like this:
-+
-+        PREROUTING:   Before NAT
-+        POSTROUTING:  Before NAT
-+
-+        More information can be found at: www.linuximq.net
-+
-+        If not sure leave the default settings alone.
-+
-+endchoice
-+
-+config IMQ_NUM_DEVS
-+      int "Number of IMQ devices"
-+      range 2 16
-+      depends on IMQ
-+      default "16"
-+      help
-+        This setting defines how many IMQ devices will be created.
-+
-+        The default value is 16.
-+
-+        More information can be found at: www.linuximq.net
-+
-+        If not sure leave the default settings alone.
-+
- config TUN
-       tristate "Universal TUN/TAP device driver support"
-       select CRC32
-diff -ruN linux-3.10.27/drivers/net/Makefile linux-3.10.27-imq/drivers/net/Makefile
---- linux-3.10.27/drivers/net/Makefile 2014-01-16 00:29:14.000000000 +0100
-+++ linux-3.10.27-imq/drivers/net/Makefile     2014-01-18 10:19:59.341342885 +0100
-@@ -9,6 +9,7 @@
- obj-$(CONFIG_DUMMY) += dummy.o
- obj-$(CONFIG_EQUALIZER) += eql.o
- obj-$(CONFIG_IFB) += ifb.o
-+obj-$(CONFIG_IMQ) += imq.o
- obj-$(CONFIG_MACVLAN) += macvlan.o
- obj-$(CONFIG_MACVTAP) += macvtap.o
- obj-$(CONFIG_MII) += mii.o
-diff -ruN linux-3.10.27/include/linux/imq.h linux-3.10.27-imq/include/linux/imq.h
---- linux-3.10.27/include/linux/imq.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.10.27-imq/include/linux/imq.h      2014-01-18 10:19:59.342342913 +0100
-@@ -0,0 +1,13 @@
-+#ifndef _IMQ_H
-+#define _IMQ_H
-+
-+/* IFMASK (16 device indexes, 0 to 15) and flag(s) fit in 5 bits */
-+#define IMQ_F_BITS    5
-+
-+#define IMQ_F_IFMASK  0x0f
-+#define IMQ_F_ENQUEUE 0x10
-+
-+#define IMQ_MAX_DEVS  (IMQ_F_IFMASK + 1)
-+
-+#endif /* _IMQ_H */
-+
-diff -ruN linux-3.10.27/include/linux/netfilter/xt_IMQ.h linux-3.10.27-imq/include/linux/netfilter/xt_IMQ.h
---- linux-3.10.27/include/linux/netfilter/xt_IMQ.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.10.27-imq/include/linux/netfilter/xt_IMQ.h 2014-01-18 10:19:59.342342913 +0100
-@@ -0,0 +1,9 @@
-+#ifndef _XT_IMQ_H
-+#define _XT_IMQ_H
-+
-+struct xt_imq_info {
-+      unsigned int todev;     /* target imq device */
-+};
-+
-+#endif /* _XT_IMQ_H */
-+
-diff -ruN linux-3.10.27/include/linux/netfilter_ipv4/ipt_IMQ.h linux-3.10.27-imq/include/linux/netfilter_ipv4/ipt_IMQ.h
---- linux-3.10.27/include/linux/netfilter_ipv4/ipt_IMQ.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.10.27-imq/include/linux/netfilter_ipv4/ipt_IMQ.h   2014-01-18 10:19:59.343342933 +0100
-@@ -0,0 +1,10 @@
-+#ifndef _IPT_IMQ_H
-+#define _IPT_IMQ_H
-+
-+/* Backwards compatibility for old userspace */
-+#include <linux/netfilter/xt_IMQ.h>
-+
-+#define ipt_imq_info xt_imq_info
-+
-+#endif /* _IPT_IMQ_H */
-+
-diff -ruN linux-3.10.27/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-3.10.27-imq/include/linux/netfilter_ipv6/ip6t_IMQ.h
---- linux-3.10.27/include/linux/netfilter_ipv6/ip6t_IMQ.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.10.27-imq/include/linux/netfilter_ipv6/ip6t_IMQ.h  2014-01-18 10:19:59.343342933 +0100
-@@ -0,0 +1,10 @@
-+#ifndef _IP6T_IMQ_H
-+#define _IP6T_IMQ_H
-+
-+/* Backwards compatibility for old userspace */
-+#include <linux/netfilter/xt_IMQ.h>
-+
-+#define ip6t_imq_info xt_imq_info
-+
-+#endif /* _IP6T_IMQ_H */
-+
-diff -ruN linux-3.10.27/include/linux/skbuff.h linux-3.10.27-imq/include/linux/skbuff.h
---- linux-3.10.27/include/linux/skbuff.h       2014-01-16 00:29:14.000000000 +0100
-+++ linux-3.10.27-imq/include/linux/skbuff.h   2014-01-18 10:18:22.220271201 +0100
-@@ -33,6 +33,9 @@
- #include <linux/dma-mapping.h>
- #include <linux/netdev_features.h>
- #include <net/flow_keys.h>
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+#include <linux/imq.h>
-+#endif
- /* Don't change this without changing skb_csum_unnecessary! */
- #define CHECKSUM_NONE 0
-@@ -414,6 +417,9 @@
-        * first. This is owned by whoever has the skb queued ATM.
-        */
-       char                    cb[48] __aligned(8);
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+      void                    *cb_next;
-+#endif
-       unsigned long           _skb_refdst;
- #ifdef CONFIG_XFRM
-@@ -449,6 +455,9 @@
- #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-       struct nf_conntrack     *nfct;
- #endif
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+      struct nf_queue_entry   *nf_queue_entry;
-+#endif
- #ifdef CONFIG_BRIDGE_NETFILTER
-       struct nf_bridge_info   *nf_bridge;
- #endif
-@@ -487,7 +496,9 @@
-       __u8                    encapsulation:1;
-       /* 7/9 bit hole (depending on ndisc_nodetype presence) */
-       kmemcheck_bitfield_end(flags2);
--
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+      __u8                    imq_flags:IMQ_F_BITS;
-+#endif
- #ifdef CONFIG_NET_DMA
-       dma_cookie_t            dma_cookie;
- #endif
-@@ -616,7 +627,10 @@
- {
-       return (struct rtable *)skb_dst(skb);
- }
--
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+extern int skb_save_cb(struct sk_buff *skb);
-+extern int skb_restore_cb(struct sk_buff *skb);
-+#endif
- extern void kfree_skb(struct sk_buff *skb);
- extern void kfree_skb_list(struct sk_buff *segs);
- extern void skb_tx_error(struct sk_buff *skb);
-@@ -2735,6 +2749,10 @@
-       nf_conntrack_get(src->nfct);
-       dst->nfctinfo = src->nfctinfo;
- #endif
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+      dst->imq_flags = src->imq_flags;
-+      dst->nf_queue_entry = src->nf_queue_entry;
-+#endif
- #ifdef CONFIG_BRIDGE_NETFILTER
-       dst->nf_bridge  = src->nf_bridge;
-       nf_bridge_get(src->nf_bridge);
-diff -ruN linux-3.10.27/include/net/netfilter/nf_queue.h linux-3.10.27-imq/include/net/netfilter/nf_queue.h
---- linux-3.10.27/include/net/netfilter/nf_queue.h     2014-01-16 00:29:14.000000000 +0100
-+++ linux-3.10.27-imq/include/net/netfilter/nf_queue.h 2014-01-18 10:19:59.345342949 +0100
-@@ -29,6 +29,12 @@
- void nf_register_queue_handler(const struct nf_queue_handler *qh);
- void nf_unregister_queue_handler(void);
- extern void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
-+extern void nf_queue_entry_release_refs(struct nf_queue_entry *entry);
-+
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+extern void nf_register_queue_imq_handler(const struct nf_queue_handler *qh);
-+extern void nf_unregister_queue_imq_handler(void);
-+#endif
- bool nf_queue_entry_get_refs(struct nf_queue_entry *entry);
- void nf_queue_entry_release_refs(struct nf_queue_entry *entry);
-diff -ruN linux-3.10.27/include/uapi/linux/netfilter.h linux-3.10.27-imq/include/uapi/linux/netfilter.h
---- linux-3.10.27/include/uapi/linux/netfilter.h       2014-01-16 00:29:14.000000000 +0100
-+++ linux-3.10.27-imq/include/uapi/linux/netfilter.h   2014-01-18 10:19:59.345342949 +0100
-@@ -13,7 +13,8 @@
- #define NF_QUEUE 3
- #define NF_REPEAT 4
- #define NF_STOP 5
--#define NF_MAX_VERDICT NF_STOP
-+#define NF_IMQ_QUEUE 6
-+#define NF_MAX_VERDICT NF_IMQ_QUEUE
- /* we overload the higher bits for encoding auxiliary data such as the queue
-  * number or errno values. Not nice, but better than additional function
-diff -ruN linux-3.10.27/net/core/dev.c linux-3.10.27-imq/net/core/dev.c
---- linux-3.10.27/net/core/dev.c       2014-01-16 00:29:14.000000000 +0100
-+++ linux-3.10.27-imq/net/core/dev.c   2014-01-18 10:19:59.347342963 +0100
-@@ -129,6 +129,9 @@
- #include <linux/inetdevice.h>
- #include <linux/cpu_rmap.h>
- #include <linux/static_key.h>
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+#include <linux/imq.h>
-+#endif
- #include "net-sysfs.h"
-@@ -2573,7 +2576,12 @@
-                       }
-               }
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+              if (!list_empty(&ptype_all) &&
-+                                      !(skb->imq_flags & IMQ_F_ENQUEUE))
-+#else
-               if (!list_empty(&ptype_all))
-+#endif
-                       dev_queue_xmit_nit(skb, dev);
-               skb_len = skb->len;
-diff -ruN linux-3.10.27/net/core/skbuff.c linux-3.10.27-imq/net/core/skbuff.c
---- linux-3.10.27/net/core/skbuff.c    2014-01-16 00:29:14.000000000 +0100
-+++ linux-3.10.27-imq/net/core/skbuff.c        2014-01-18 10:19:59.348342972 +0100
-@@ -73,6 +73,9 @@
- struct kmem_cache *skbuff_head_cache __read_mostly;
- static struct kmem_cache *skbuff_fclone_cache __read_mostly;
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+static struct kmem_cache *skbuff_cb_store_cache __read_mostly;
-+#endif
- static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
-                                 struct pipe_buffer *buf)
-@@ -92,6 +95,82 @@
-       return 1;
- }
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+/* Control buffer save/restore for IMQ devices */
-+struct skb_cb_table {
-+      char                    cb[48] __aligned(8);
-+      void                    *cb_next;
-+      atomic_t                refcnt;
-+};
-+
-+static DEFINE_SPINLOCK(skb_cb_store_lock);
-+
-+int skb_save_cb(struct sk_buff *skb)
-+{
-+      struct skb_cb_table *next;
-+
-+      next = kmem_cache_alloc(skbuff_cb_store_cache, GFP_ATOMIC);
-+      if (!next)
-+              return -ENOMEM;
-+
-+      BUILD_BUG_ON(sizeof(skb->cb) != sizeof(next->cb));
-+
-+      memcpy(next->cb, skb->cb, sizeof(skb->cb));
-+      next->cb_next = skb->cb_next;
-+
-+      atomic_set(&next->refcnt, 1);
-+
-+      skb->cb_next = next;
-+      return 0;
-+}
-+EXPORT_SYMBOL(skb_save_cb);
-+
-+int skb_restore_cb(struct sk_buff *skb)
-+{
-+      struct skb_cb_table *next;
-+
-+      if (!skb->cb_next)
-+              return 0;
-+
-+      next = skb->cb_next;
-+
-+      BUILD_BUG_ON(sizeof(skb->cb) != sizeof(next->cb));
-+
-+      memcpy(skb->cb, next->cb, sizeof(skb->cb));
-+      skb->cb_next = next->cb_next;
-+
-+      spin_lock(&skb_cb_store_lock);
-+
-+      if (atomic_dec_and_test(&next->refcnt))
-+              kmem_cache_free(skbuff_cb_store_cache, next);
-+
-+      spin_unlock(&skb_cb_store_lock);
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(skb_restore_cb);
-+
-+static void skb_copy_stored_cb(struct sk_buff *new, const struct sk_buff *__old)
-+{
-+      struct skb_cb_table *next;
-+      struct sk_buff *old;
-+
-+      if (!__old->cb_next) {
-+              new->cb_next = NULL;
-+              return;
-+      }
-+
-+      spin_lock(&skb_cb_store_lock);
-+
-+      old = (struct sk_buff *)__old;
-+
-+      next = old->cb_next;
-+      atomic_inc(&next->refcnt);
-+      new->cb_next = next;
-+
-+      spin_unlock(&skb_cb_store_lock);
-+}
-+#endif
- /* Pipe buffer operations for a socket. */
- static const struct pipe_buf_operations sock_pipe_buf_ops = {
-@@ -582,6 +661,28 @@
-               WARN_ON(in_irq());
-               skb->destructor(skb);
-       }
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+      /*
-+       * This should not happen. When it does, avoid memleak by restoring
-+       * the chain of cb-backups.
-+       */
-+      while (skb->cb_next != NULL) {
-+              if (net_ratelimit())
-+                      pr_warn("IMQ: kfree_skb: skb->cb_next: %08x\n",
-+                              (unsigned int)skb->cb_next);
-+
-+              skb_restore_cb(skb);
-+      }
-+      /*
-+       * This should not happen either, nf_queue_entry is nullified in
-+       * imq_dev_xmit(). If we have non-NULL nf_queue_entry then we are
-+       * leaking entry pointers, maybe memory. We don't know if this is
-+       * pointer to already freed memory, or should this be freed.
-+       * If this happens we need to add refcounting, etc for nf_queue_entry.
-+       */
-+      if (skb->nf_queue_entry && net_ratelimit())
-+              pr_warn("%s\n", "IMQ: kfree_skb: skb->nf_queue_entry != NULL");
-+#endif
- #if IS_ENABLED(CONFIG_NF_CONNTRACK)
-       nf_conntrack_put(skb->nfct);
- #endif
-@@ -713,6 +814,10 @@
-       new->sp                 = secpath_get(old->sp);
- #endif
-       memcpy(new->cb, old->cb, sizeof(old->cb));
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+      new->cb_next = NULL;
-+      /*skb_copy_stored_cb(new, old);*/
-+#endif
-       new->csum               = old->csum;
-       new->local_df           = old->local_df;
-       new->pkt_type           = old->pkt_type;
-@@ -3093,6 +3198,13 @@
-                                               0,
-                                               SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-                                               NULL);
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+      skbuff_cb_store_cache = kmem_cache_create("skbuff_cb_store_cache",
-+                                                sizeof(struct skb_cb_table),
-+                                                0,
-+                                                SLAB_HWCACHE_ALIGN|SLAB_PANIC,
-+                                                NULL);
-+#endif
- }
- /**
-diff -ruN linux-3.10.27/net/core/skbuff.c.orig linux-3.10.27-imq/net/core/skbuff.c.orig
---- linux-3.10.27/net/core/skbuff.c.orig       1970-01-01 01:00:00.000000000 +0100
-+++ linux-3.10.27-imq/net/core/skbuff.c.orig   2014-01-16 00:29:14.000000000 +0100
-@@ -0,0 +1,3503 @@
-+/*
-+ *    Routines having to do with the 'struct sk_buff' memory handlers.
-+ *
-+ *    Authors:        Alan Cox <alan@lxorguk.ukuu.org.uk>
-+ *                    Florian La Roche <rzsfl@rz.uni-sb.de>
-+ *
-+ *    Fixes:
-+ *            Alan Cox        :       Fixed the worst of the load
-+ *                                    balancer bugs.
-+ *            Dave Platt      :       Interrupt stacking fix.
-+ *    Richard Kooijman        :       Timestamp fixes.
-+ *            Alan Cox        :       Changed buffer format.
-+ *            Alan Cox        :       destructor hook for AF_UNIX etc.
-+ *            Linus Torvalds  :       Better skb_clone.
-+ *            Alan Cox        :       Added skb_copy.
-+ *            Alan Cox        :       Added all the changed routines Linus
-+ *                                    only put in the headers
-+ *            Ray VanTassle   :       Fixed --skb->lock in free
-+ *            Alan Cox        :       skb_copy copy arp field
-+ *            Andi Kleen      :       slabified it.
-+ *            Robert Olsson   :       Removed skb_head_pool
-+ *
-+ *    NOTE:
-+ *            The __skb_ routines should be called with interrupts
-+ *    disabled, or you better be *real* sure that the operation is atomic
-+ *    with respect to whatever list is being frobbed (e.g. via lock_sock()
-+ *    or via disabling bottom half handlers, etc).
-+ *
-+ *    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.
-+ */
-+
-+/*
-+ *    The functions in this file will not compile correctly with gcc 2.4.x
-+ */
-+
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/kmemcheck.h>
-+#include <linux/mm.h>
-+#include <linux/interrupt.h>
-+#include <linux/in.h>
-+#include <linux/inet.h>
-+#include <linux/slab.h>
-+#include <linux/netdevice.h>
-+#ifdef CONFIG_NET_CLS_ACT
-+#include <net/pkt_sched.h>
-+#endif
-+#include <linux/string.h>
-+#include <linux/skbuff.h>
-+#include <linux/splice.h>
-+#include <linux/cache.h>
-+#include <linux/rtnetlink.h>
-+#include <linux/init.h>
-+#include <linux/scatterlist.h>
-+#include <linux/errqueue.h>
-+#include <linux/prefetch.h>
-+
-+#include <net/protocol.h>
-+#include <net/dst.h>
-+#include <net/sock.h>
-+#include <net/checksum.h>
-+#include <net/xfrm.h>
-+
-+#include <asm/uaccess.h>
-+#include <trace/events/skb.h>
-+#include <linux/highmem.h>
-+
-+struct kmem_cache *skbuff_head_cache __read_mostly;
-+static struct kmem_cache *skbuff_fclone_cache __read_mostly;
-+
-+static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
-+                                struct pipe_buffer *buf)
-+{
-+      put_page(buf->page);
-+}
-+
-+static void sock_pipe_buf_get(struct pipe_inode_info *pipe,
-+                              struct pipe_buffer *buf)
-+{
-+      get_page(buf->page);
-+}
-+
-+static int sock_pipe_buf_steal(struct pipe_inode_info *pipe,
-+                             struct pipe_buffer *buf)
-+{
-+      return 1;
-+}
-+
-+
-+/* Pipe buffer operations for a socket. */
-+static const struct pipe_buf_operations sock_pipe_buf_ops = {
-+      .can_merge = 0,
-+      .map = generic_pipe_buf_map,
-+      .unmap = generic_pipe_buf_unmap,
-+      .confirm = generic_pipe_buf_confirm,
-+      .release = sock_pipe_buf_release,
-+      .steal = sock_pipe_buf_steal,
-+      .get = sock_pipe_buf_get,
-+};
-+
-+/**
-+ *    skb_panic - private function for out-of-line support
-+ *    @skb:   buffer
-+ *    @sz:    size
-+ *    @addr:  address
-+ *    @msg:   skb_over_panic or skb_under_panic
-+ *
-+ *    Out-of-line support for skb_put() and skb_push().
-+ *    Called via the wrapper skb_over_panic() or skb_under_panic().
-+ *    Keep out of line to prevent kernel bloat.
-+ *    __builtin_return_address is not used because it is not always reliable.
-+ */
-+static void skb_panic(struct sk_buff *skb, unsigned int sz, void *addr,
-+                    const char msg[])
-+{
-+      pr_emerg("%s: text:%p len:%d put:%d head:%p data:%p tail:%#lx end:%#lx dev:%s\n",
-+               msg, addr, skb->len, sz, skb->head, skb->data,
-+               (unsigned long)skb->tail, (unsigned long)skb->end,
-+               skb->dev ? skb->dev->name : "<NULL>");
-+      BUG();
-+}
-+
-+static void skb_over_panic(struct sk_buff *skb, unsigned int sz, void *addr)
-+{
-+      skb_panic(skb, sz, addr, __func__);
-+}
-+
-+static void skb_under_panic(struct sk_buff *skb, unsigned int sz, void *addr)
-+{
-+      skb_panic(skb, sz, addr, __func__);
-+}
-+
-+/*
-+ * kmalloc_reserve is a wrapper around kmalloc_node_track_caller that tells
-+ * the caller if emergency pfmemalloc reserves are being used. If it is and
-+ * the socket is later found to be SOCK_MEMALLOC then PFMEMALLOC reserves
-+ * may be used. Otherwise, the packet data may be discarded until enough
-+ * memory is free
-+ */
-+#define kmalloc_reserve(size, gfp, node, pfmemalloc) \
-+       __kmalloc_reserve(size, gfp, node, _RET_IP_, pfmemalloc)
-+
-+static void *__kmalloc_reserve(size_t size, gfp_t flags, int node,
-+                             unsigned long ip, bool *pfmemalloc)
-+{
-+      void *obj;
-+      bool ret_pfmemalloc = false;
-+
-+      /*
-+       * Try a regular allocation, when that fails and we're not entitled
-+       * to the reserves, fail.
-+       */
-+      obj = kmalloc_node_track_caller(size,
-+                                      flags | __GFP_NOMEMALLOC | __GFP_NOWARN,
-+                                      node);
-+      if (obj || !(gfp_pfmemalloc_allowed(flags)))
-+              goto out;
-+
-+      /* Try again but now we are using pfmemalloc reserves */
-+      ret_pfmemalloc = true;
-+      obj = kmalloc_node_track_caller(size, flags, node);
-+
-+out:
-+      if (pfmemalloc)
-+              *pfmemalloc = ret_pfmemalloc;
-+
-+      return obj;
-+}
-+
-+/*    Allocate a new skbuff. We do this ourselves so we can fill in a few
-+ *    'private' fields and also do memory statistics to find all the
-+ *    [BEEP] leaks.
-+ *
-+ */
-+
-+struct sk_buff *__alloc_skb_head(gfp_t gfp_mask, int node)
-+{
-+      struct sk_buff *skb;
-+
-+      /* Get the HEAD */
-+      skb = kmem_cache_alloc_node(skbuff_head_cache,
-+                                  gfp_mask & ~__GFP_DMA, node);
-+      if (!skb)
-+              goto out;
-+
-+      /*
-+       * Only clear those fields we need to clear, not those that we will
-+       * actually initialise below. Hence, don't put any more fields after
-+       * the tail pointer in struct sk_buff!
-+       */
-+      memset(skb, 0, offsetof(struct sk_buff, tail));
-+      skb->head = NULL;
-+      skb->truesize = sizeof(struct sk_buff);
-+      atomic_set(&skb->users, 1);
-+
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+      skb->mac_header = ~0U;
-+#endif
-+out:
-+      return skb;
-+}
-+
-+/**
-+ *    __alloc_skb     -       allocate a network buffer
-+ *    @size: size to allocate
-+ *    @gfp_mask: allocation mask
-+ *    @flags: If SKB_ALLOC_FCLONE is set, allocate from fclone cache
-+ *            instead of head cache and allocate a cloned (child) skb.
-+ *            If SKB_ALLOC_RX is set, __GFP_MEMALLOC will be used for
-+ *            allocations in case the data is required for writeback
-+ *    @node: numa node to allocate memory on
-+ *
-+ *    Allocate a new &sk_buff. The returned buffer has no headroom and a
-+ *    tail room of at least size bytes. The object has a reference count
-+ *    of one. The return is the buffer. On a failure the return is %NULL.
-+ *
-+ *    Buffers may only be allocated from interrupts using a @gfp_mask of
-+ *    %GFP_ATOMIC.
-+ */
-+struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
-+                          int flags, int node)
-+{
-+      struct kmem_cache *cache;
-+      struct skb_shared_info *shinfo;
-+      struct sk_buff *skb;
-+      u8 *data;
-+      bool pfmemalloc;
-+
-+      cache = (flags & SKB_ALLOC_FCLONE)
-+              ? skbuff_fclone_cache : skbuff_head_cache;
-+
-+      if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX))
-+              gfp_mask |= __GFP_MEMALLOC;
-+
-+      /* Get the HEAD */
-+      skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
-+      if (!skb)
-+              goto out;
-+      prefetchw(skb);
-+
-+      /* We do our best to align skb_shared_info on a separate cache
-+       * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
-+       * aligned memory blocks, unless SLUB/SLAB debug is enabled.
-+       * Both skb->head and skb_shared_info are cache line aligned.
-+       */
-+      size = SKB_DATA_ALIGN(size);
-+      size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
-+      data = kmalloc_reserve(size, gfp_mask, node, &pfmemalloc);
-+      if (!data)
-+              goto nodata;
-+      /* kmalloc(size) might give us more room than requested.
-+       * Put skb_shared_info exactly at the end of allocated zone,
-+       * to allow max possible filling before reallocation.
-+       */
-+      size = SKB_WITH_OVERHEAD(ksize(data));
-+      prefetchw(data + size);
-+
-+      /*
-+       * Only clear those fields we need to clear, not those that we will
-+       * actually initialise below. Hence, don't put any more fields after
-+       * the tail pointer in struct sk_buff!
-+       */
-+      memset(skb, 0, offsetof(struct sk_buff, tail));
-+      /* Account for allocated memory : skb + skb->head */
-+      skb->truesize = SKB_TRUESIZE(size);
-+      skb->pfmemalloc = pfmemalloc;
-+      atomic_set(&skb->users, 1);
-+      skb->head = data;
-+      skb->data = data;
-+      skb_reset_tail_pointer(skb);
-+      skb->end = skb->tail + size;
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+      skb->mac_header = ~0U;
-+      skb->transport_header = ~0U;
-+#endif
-+
-+      /* make sure we initialize shinfo sequentially */
-+      shinfo = skb_shinfo(skb);
-+      memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
-+      atomic_set(&shinfo->dataref, 1);
-+      kmemcheck_annotate_variable(shinfo->destructor_arg);
-+
-+      if (flags & SKB_ALLOC_FCLONE) {
-+              struct sk_buff *child = skb + 1;
-+              atomic_t *fclone_ref = (atomic_t *) (child + 1);
-+
-+              kmemcheck_annotate_bitfield(child, flags1);
-+              kmemcheck_annotate_bitfield(child, flags2);
-+              skb->fclone = SKB_FCLONE_ORIG;
-+              atomic_set(fclone_ref, 1);
-+
-+              child->fclone = SKB_FCLONE_UNAVAILABLE;
-+              child->pfmemalloc = pfmemalloc;
-+      }
-+out:
-+      return skb;
-+nodata:
-+      kmem_cache_free(cache, skb);
-+      skb = NULL;
-+      goto out;
-+}
-+EXPORT_SYMBOL(__alloc_skb);
-+
-+/**
-+ * build_skb - build a network buffer
-+ * @data: data buffer provided by caller
-+ * @frag_size: size of fragment, or 0 if head was kmalloced
-+ *
-+ * Allocate a new &sk_buff. Caller provides space holding head and
-+ * skb_shared_info. @data must have been allocated by kmalloc()
-+ * The return is the new skb buffer.
-+ * On a failure the return is %NULL, and @data is not freed.
-+ * Notes :
-+ *  Before IO, driver allocates only data buffer where NIC put incoming frame
-+ *  Driver should add room at head (NET_SKB_PAD) and
-+ *  MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
-+ *  After IO, driver calls build_skb(), to allocate sk_buff and populate it
-+ *  before giving packet to stack.
-+ *  RX rings only contains data buffers, not full skbs.
-+ */
-+struct sk_buff *build_skb(void *data, unsigned int frag_size)
-+{
-+      struct skb_shared_info *shinfo;
-+      struct sk_buff *skb;
-+      unsigned int size = frag_size ? : ksize(data);
-+
-+      skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
-+      if (!skb)
-+              return NULL;
-+
-+      size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
-+
-+      memset(skb, 0, offsetof(struct sk_buff, tail));
-+      skb->truesize = SKB_TRUESIZE(size);
-+      skb->head_frag = frag_size != 0;
-+      atomic_set(&skb->users, 1);
-+      skb->head = data;
-+      skb->data = data;
-+      skb_reset_tail_pointer(skb);
-+      skb->end = skb->tail + size;
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+      skb->mac_header = ~0U;
-+      skb->transport_header = ~0U;
-+#endif
-+
-+      /* make sure we initialize shinfo sequentially */
-+      shinfo = skb_shinfo(skb);
-+      memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
-+      atomic_set(&shinfo->dataref, 1);
-+      kmemcheck_annotate_variable(shinfo->destructor_arg);
-+
-+      return skb;
-+}
-+EXPORT_SYMBOL(build_skb);
-+
-+struct netdev_alloc_cache {
-+      struct page_frag        frag;
-+      /* we maintain a pagecount bias, so that we dont dirty cache line
-+       * containing page->_count every time we allocate a fragment.
-+       */
-+      unsigned int            pagecnt_bias;
-+};
-+static DEFINE_PER_CPU(struct netdev_alloc_cache, netdev_alloc_cache);
-+
-+static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
-+{
-+      struct netdev_alloc_cache *nc;
-+      void *data = NULL;
-+      int order;
-+      unsigned long flags;
-+
-+      local_irq_save(flags);
-+      nc = &__get_cpu_var(netdev_alloc_cache);
-+      if (unlikely(!nc->frag.page)) {
-+refill:
-+              for (order = NETDEV_FRAG_PAGE_MAX_ORDER; ;) {
-+                      gfp_t gfp = gfp_mask;
-+
-+                      if (order)
-+                              gfp |= __GFP_COMP | __GFP_NOWARN;
-+                      nc->frag.page = alloc_pages(gfp, order);
-+                      if (likely(nc->frag.page))
-+                              break;
-+                      if (--order < 0)
-+                              goto end;
-+              }
-+              nc->frag.size = PAGE_SIZE << order;
-+recycle:
-+              atomic_set(&nc->frag.page->_count, NETDEV_PAGECNT_MAX_BIAS);
-+              nc->pagecnt_bias = NETDEV_PAGECNT_MAX_BIAS;
-+              nc->frag.offset = 0;
-+      }
-+
-+      if (nc->frag.offset + fragsz > nc->frag.size) {
-+              /* avoid unnecessary locked operations if possible */
-+              if ((atomic_read(&nc->frag.page->_count) == nc->pagecnt_bias) ||
-+                  atomic_sub_and_test(nc->pagecnt_bias, &nc->frag.page->_count))
-+                      goto recycle;
-+              goto refill;
-+      }
-+
-+      data = page_address(nc->frag.page) + nc->frag.offset;
-+      nc->frag.offset += fragsz;
-+      nc->pagecnt_bias--;
-+end:
-+      local_irq_restore(flags);
-+      return data;
-+}
-+
-+/**
-+ * netdev_alloc_frag - allocate a page fragment
-+ * @fragsz: fragment size
-+ *
-+ * Allocates a frag from a page for receive buffer.
-+ * Uses GFP_ATOMIC allocations.
-+ */
-+void *netdev_alloc_frag(unsigned int fragsz)
-+{
-+      return __netdev_alloc_frag(fragsz, GFP_ATOMIC | __GFP_COLD);
-+}
-+EXPORT_SYMBOL(netdev_alloc_frag);
-+
-+/**
-+ *    __netdev_alloc_skb - allocate an skbuff for rx on a specific device
-+ *    @dev: network device to receive on
-+ *    @length: length to allocate
-+ *    @gfp_mask: get_free_pages mask, passed to alloc_skb
-+ *
-+ *    Allocate a new &sk_buff and assign it a usage count of one. The
-+ *    buffer has unspecified headroom built in. Users should allocate
-+ *    the headroom they think they need without accounting for the
-+ *    built in space. The built in space is used for optimisations.
-+ *
-+ *    %NULL is returned if there is no free memory.
-+ */
-+struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
-+                                 unsigned int length, gfp_t gfp_mask)
-+{
-+      struct sk_buff *skb = NULL;
-+      unsigned int fragsz = SKB_DATA_ALIGN(length + NET_SKB_PAD) +
-+                            SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
-+
-+      if (fragsz <= PAGE_SIZE && !(gfp_mask & (__GFP_WAIT | GFP_DMA))) {
-+              void *data;
-+
-+              if (sk_memalloc_socks())
-+                      gfp_mask |= __GFP_MEMALLOC;
-+
-+              data = __netdev_alloc_frag(fragsz, gfp_mask);
-+
-+              if (likely(data)) {
-+                      skb = build_skb(data, fragsz);
-+                      if (unlikely(!skb))
-+                              put_page(virt_to_head_page(data));
-+              }
-+      } else {
-+              skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask,
-+                                SKB_ALLOC_RX, NUMA_NO_NODE);
-+      }
-+      if (likely(skb)) {
-+              skb_reserve(skb, NET_SKB_PAD);
-+              skb->dev = dev;
-+      }
-+      return skb;
-+}
-+EXPORT_SYMBOL(__netdev_alloc_skb);
-+
-+void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
-+                   int size, unsigned int truesize)
-+{
-+      skb_fill_page_desc(skb, i, page, off, size);
-+      skb->len += size;
-+      skb->data_len += size;
-+      skb->truesize += truesize;
-+}
-+EXPORT_SYMBOL(skb_add_rx_frag);
-+
-+static void skb_drop_list(struct sk_buff **listp)
-+{
-+      kfree_skb_list(*listp);
-+      *listp = NULL;
-+}
-+
-+static inline void skb_drop_fraglist(struct sk_buff *skb)
-+{
-+      skb_drop_list(&skb_shinfo(skb)->frag_list);
-+}
-+
-+static void skb_clone_fraglist(struct sk_buff *skb)
-+{
-+      struct sk_buff *list;
-+
-+      skb_walk_frags(skb, list)
-+              skb_get(list);
-+}
-+
-+static void skb_free_head(struct sk_buff *skb)
-+{
-+      if (skb->head_frag)
-+              put_page(virt_to_head_page(skb->head));
-+      else
-+              kfree(skb->head);
-+}
-+
-+static void skb_release_data(struct sk_buff *skb)
-+{
-+      if (!skb->cloned ||
-+          !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1,
-+                             &skb_shinfo(skb)->dataref)) {
-+              if (skb_shinfo(skb)->nr_frags) {
-+                      int i;
-+                      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-+                              skb_frag_unref(skb, i);
-+              }
-+
-+              /*
-+               * If skb buf is from userspace, we need to notify the caller
-+               * the lower device DMA has done;
-+               */
-+              if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
-+                      struct ubuf_info *uarg;
-+
-+                      uarg = skb_shinfo(skb)->destructor_arg;
-+                      if (uarg->callback)
-+                              uarg->callback(uarg, true);
-+              }
-+
-+              if (skb_has_frag_list(skb))
-+                      skb_drop_fraglist(skb);
-+
-+              skb_free_head(skb);
-+      }
-+}
-+
-+/*
-+ *    Free an skbuff by memory without cleaning the state.
-+ */
-+static void kfree_skbmem(struct sk_buff *skb)
-+{
-+      struct sk_buff *other;
-+      atomic_t *fclone_ref;
-+
-+      switch (skb->fclone) {
-+      case SKB_FCLONE_UNAVAILABLE:
-+              kmem_cache_free(skbuff_head_cache, skb);
-+              break;
-+
-+      case SKB_FCLONE_ORIG:
-+              fclone_ref = (atomic_t *) (skb + 2);
-+              if (atomic_dec_and_test(fclone_ref))
-+                      kmem_cache_free(skbuff_fclone_cache, skb);
-+              break;
-+
-+      case SKB_FCLONE_CLONE:
-+              fclone_ref = (atomic_t *) (skb + 1);
-+              other = skb - 1;
-+
-+              /* The clone portion is available for
-+               * fast-cloning again.
-+               */
-+              skb->fclone = SKB_FCLONE_UNAVAILABLE;
-+
-+              if (atomic_dec_and_test(fclone_ref))
-+                      kmem_cache_free(skbuff_fclone_cache, other);
-+              break;
-+      }
-+}
-+
-+static void skb_release_head_state(struct sk_buff *skb)
-+{
-+      skb_dst_drop(skb);
-+#ifdef CONFIG_XFRM
-+      secpath_put(skb->sp);
-+#endif
-+      if (skb->destructor) {
-+              WARN_ON(in_irq());
-+              skb->destructor(skb);
-+      }
-+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
-+      nf_conntrack_put(skb->nfct);
-+#endif
-+#ifdef CONFIG_BRIDGE_NETFILTER
-+      nf_bridge_put(skb->nf_bridge);
-+#endif
-+/* XXX: IS this still necessary? - JHS */
-+#ifdef CONFIG_NET_SCHED
-+      skb->tc_index = 0;
-+#ifdef CONFIG_NET_CLS_ACT
-+      skb->tc_verd = 0;
-+#endif
-+#endif
-+}
-+
-+/* Free everything but the sk_buff shell. */
-+static void skb_release_all(struct sk_buff *skb)
-+{
-+      skb_release_head_state(skb);
-+      if (likely(skb->head))
-+              skb_release_data(skb);
-+}
-+
-+/**
-+ *    __kfree_skb - private function
-+ *    @skb: buffer
-+ *
-+ *    Free an sk_buff. Release anything attached to the buffer.
-+ *    Clean the state. This is an internal helper function. Users should
-+ *    always call kfree_skb
-+ */
-+
-+void __kfree_skb(struct sk_buff *skb)
-+{
-+      skb_release_all(skb);
-+      kfree_skbmem(skb);
-+}
-+EXPORT_SYMBOL(__kfree_skb);
-+
-+/**
-+ *    kfree_skb - free an sk_buff
-+ *    @skb: buffer to free
-+ *
-+ *    Drop a reference to the buffer and free it if the usage count has
-+ *    hit zero.
-+ */
-+void kfree_skb(struct sk_buff *skb)
-+{
-+      if (unlikely(!skb))
-+              return;
-+      if (likely(atomic_read(&skb->users) == 1))
-+              smp_rmb();
-+      else if (likely(!atomic_dec_and_test(&skb->users)))
-+              return;
-+      trace_kfree_skb(skb, __builtin_return_address(0));
-+      __kfree_skb(skb);
-+}
-+EXPORT_SYMBOL(kfree_skb);
-+
-+void kfree_skb_list(struct sk_buff *segs)
-+{
-+      while (segs) {
-+              struct sk_buff *next = segs->next;
-+
-+              kfree_skb(segs);
-+              segs = next;
-+      }
-+}
-+EXPORT_SYMBOL(kfree_skb_list);
-+
-+/**
-+ *    skb_tx_error - report an sk_buff xmit error
-+ *    @skb: buffer that triggered an error
-+ *
-+ *    Report xmit error if a device callback is tracking this skb.
-+ *    skb must be freed afterwards.
-+ */
-+void skb_tx_error(struct sk_buff *skb)
-+{
-+      if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) {
-+              struct ubuf_info *uarg;
-+
-+              uarg = skb_shinfo(skb)->destructor_arg;
-+              if (uarg->callback)
-+                      uarg->callback(uarg, false);
-+              skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
-+      }
-+}
-+EXPORT_SYMBOL(skb_tx_error);
-+
-+/**
-+ *    consume_skb - free an skbuff
-+ *    @skb: buffer to free
-+ *
-+ *    Drop a ref to the buffer and free it if the usage count has hit zero
-+ *    Functions identically to kfree_skb, but kfree_skb assumes that the frame
-+ *    is being dropped after a failure and notes that
-+ */
-+void consume_skb(struct sk_buff *skb)
-+{
-+      if (unlikely(!skb))
-+              return;
-+      if (likely(atomic_read(&skb->users) == 1))
-+              smp_rmb();
-+      else if (likely(!atomic_dec_and_test(&skb->users)))
-+              return;
-+      trace_consume_skb(skb);
-+      __kfree_skb(skb);
-+}
-+EXPORT_SYMBOL(consume_skb);
-+
-+static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
-+{
-+      new->tstamp             = old->tstamp;
-+      new->dev                = old->dev;
-+      new->transport_header   = old->transport_header;
-+      new->network_header     = old->network_header;
-+      new->mac_header         = old->mac_header;
-+      new->inner_transport_header = old->inner_transport_header;
-+      new->inner_network_header = old->inner_network_header;
-+      new->inner_mac_header = old->inner_mac_header;
-+      skb_dst_copy(new, old);
-+      new->rxhash             = old->rxhash;
-+      new->ooo_okay           = old->ooo_okay;
-+      new->l4_rxhash          = old->l4_rxhash;
-+      new->no_fcs             = old->no_fcs;
-+      new->encapsulation      = old->encapsulation;
-+#ifdef CONFIG_XFRM
-+      new->sp                 = secpath_get(old->sp);
-+#endif
-+      memcpy(new->cb, old->cb, sizeof(old->cb));
-+      new->csum               = old->csum;
-+      new->local_df           = old->local_df;
-+      new->pkt_type           = old->pkt_type;
-+      new->ip_summed          = old->ip_summed;
-+      skb_copy_queue_mapping(new, old);
-+      new->priority           = old->priority;
-+#if IS_ENABLED(CONFIG_IP_VS)
-+      new->ipvs_property      = old->ipvs_property;
-+#endif
-+      new->pfmemalloc         = old->pfmemalloc;
-+      new->protocol           = old->protocol;
-+      new->mark               = old->mark;
-+      new->skb_iif            = old->skb_iif;
-+      __nf_copy(new, old);
-+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-+      new->nf_trace           = old->nf_trace;
-+#endif
-+#ifdef CONFIG_NET_SCHED
-+      new->tc_index           = old->tc_index;
-+#ifdef CONFIG_NET_CLS_ACT
-+      new->tc_verd            = old->tc_verd;
-+#endif
-+#endif
-+      new->vlan_proto         = old->vlan_proto;
-+      new->vlan_tci           = old->vlan_tci;
-+
-+      skb_copy_secmark(new, old);
-+}
-+
-+/*
-+ * You should not add any new code to this function.  Add it to
-+ * __copy_skb_header above instead.
-+ */
-+static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
-+{
-+#define C(x) n->x = skb->x
-+
-+      n->next = n->prev = NULL;
-+      n->sk = NULL;
-+      __copy_skb_header(n, skb);
-+
-+      C(len);
-+      C(data_len);
-+      C(mac_len);
-+      n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
-+      n->cloned = 1;
-+      n->nohdr = 0;
-+      n->destructor = NULL;
-+      C(tail);
-+      C(end);
-+      C(head);
-+      C(head_frag);
-+      C(data);
-+      C(truesize);
-+      atomic_set(&n->users, 1);
-+
-+      atomic_inc(&(skb_shinfo(skb)->dataref));
-+      skb->cloned = 1;
-+
-+      return n;
-+#undef C
-+}
-+
-+/**
-+ *    skb_morph       -       morph one skb into another
-+ *    @dst: the skb to receive the contents
-+ *    @src: the skb to supply the contents
-+ *
-+ *    This is identical to skb_clone except that the target skb is
-+ *    supplied by the user.
-+ *
-+ *    The target skb is returned upon exit.
-+ */
-+struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
-+{
-+      skb_release_all(dst);
-+      return __skb_clone(dst, src);
-+}
-+EXPORT_SYMBOL_GPL(skb_morph);
-+
-+/**
-+ *    skb_copy_ubufs  -       copy userspace skb frags buffers to kernel
-+ *    @skb: the skb to modify
-+ *    @gfp_mask: allocation priority
-+ *
-+ *    This must be called on SKBTX_DEV_ZEROCOPY skb.
-+ *    It will copy all frags into kernel and drop the reference
-+ *    to userspace pages.
-+ *
-+ *    If this function is called from an interrupt gfp_mask() must be
-+ *    %GFP_ATOMIC.
-+ *
-+ *    Returns 0 on success or a negative error code on failure
-+ *    to allocate kernel memory to copy to.
-+ */
-+int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
-+{
-+      int i;
-+      int num_frags = skb_shinfo(skb)->nr_frags;
-+      struct page *page, *head = NULL;
-+      struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
-+
-+      for (i = 0; i < num_frags; i++) {
-+              u8 *vaddr;
-+              skb_frag_t *f = &skb_shinfo(skb)->frags[i];
-+
-+              page = alloc_page(gfp_mask);
-+              if (!page) {
-+                      while (head) {
-+                              struct page *next = (struct page *)head->private;
-+                              put_page(head);
-+                              head = next;
-+                      }
-+                      return -ENOMEM;
-+              }
-+              vaddr = kmap_atomic(skb_frag_page(f));
-+              memcpy(page_address(page),
-+                     vaddr + f->page_offset, skb_frag_size(f));
-+              kunmap_atomic(vaddr);
-+              page->private = (unsigned long)head;
-+              head = page;
-+      }
-+
-+      /* skb frags release userspace buffers */
-+      for (i = 0; i < num_frags; i++)
-+              skb_frag_unref(skb, i);
-+
-+      uarg->callback(uarg, false);
-+
-+      /* skb frags point to kernel buffers */
-+      for (i = num_frags - 1; i >= 0; i--) {
-+              __skb_fill_page_desc(skb, i, head, 0,
-+                                   skb_shinfo(skb)->frags[i].size);
-+              head = (struct page *)head->private;
-+      }
-+
-+      skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(skb_copy_ubufs);
-+
-+/**
-+ *    skb_clone       -       duplicate an sk_buff
-+ *    @skb: buffer to clone
-+ *    @gfp_mask: allocation priority
-+ *
-+ *    Duplicate an &sk_buff. The new one is not owned by a socket. Both
-+ *    copies share the same packet data but not structure. The new
-+ *    buffer has a reference count of 1. If the allocation fails the
-+ *    function returns %NULL otherwise the new buffer is returned.
-+ *
-+ *    If this function is called from an interrupt gfp_mask() must be
-+ *    %GFP_ATOMIC.
-+ */
-+
-+struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
-+{
-+      struct sk_buff *n;
-+
-+      if (skb_orphan_frags(skb, gfp_mask))
-+              return NULL;
-+
-+      n = skb + 1;
-+      if (skb->fclone == SKB_FCLONE_ORIG &&
-+          n->fclone == SKB_FCLONE_UNAVAILABLE) {
-+              atomic_t *fclone_ref = (atomic_t *) (n + 1);
-+              n->fclone = SKB_FCLONE_CLONE;
-+              atomic_inc(fclone_ref);
-+      } else {
-+              if (skb_pfmemalloc(skb))
-+                      gfp_mask |= __GFP_MEMALLOC;
-+
-+              n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
-+              if (!n)
-+                      return NULL;
-+
-+              kmemcheck_annotate_bitfield(n, flags1);
-+              kmemcheck_annotate_bitfield(n, flags2);
-+              n->fclone = SKB_FCLONE_UNAVAILABLE;
-+      }
-+
-+      return __skb_clone(n, skb);
-+}
-+EXPORT_SYMBOL(skb_clone);
-+
-+static void skb_headers_offset_update(struct sk_buff *skb, int off)
-+{
-+      /* {transport,network,mac}_header and tail are relative to skb->head */
-+      skb->transport_header += off;
-+      skb->network_header   += off;
-+      if (skb_mac_header_was_set(skb))
-+              skb->mac_header += off;
-+      skb->inner_transport_header += off;
-+      skb->inner_network_header += off;
-+      skb->inner_mac_header += off;
-+}
-+
-+static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
-+{
-+#ifndef NET_SKBUFF_DATA_USES_OFFSET
-+      /*
-+       *      Shift between the two data areas in bytes
-+       */
-+      unsigned long offset = new->data - old->data;
-+#endif
-+
-+      __copy_skb_header(new, old);
-+
-+#ifndef NET_SKBUFF_DATA_USES_OFFSET
-+      skb_headers_offset_update(new, offset);
-+#endif
-+      skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
-+      skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
-+      skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
-+}
-+
-+static inline int skb_alloc_rx_flag(const struct sk_buff *skb)
-+{
-+      if (skb_pfmemalloc(skb))
-+              return SKB_ALLOC_RX;
-+      return 0;
-+}
-+
-+/**
-+ *    skb_copy        -       create private copy of an sk_buff
-+ *    @skb: buffer to copy
-+ *    @gfp_mask: allocation priority
-+ *
-+ *    Make a copy of both an &sk_buff and its data. This is used when the
-+ *    caller wishes to modify the data and needs a private copy of the
-+ *    data to alter. Returns %NULL on failure or the pointer to the buffer
-+ *    on success. The returned buffer has a reference count of 1.
-+ *
-+ *    As by-product this function converts non-linear &sk_buff to linear
-+ *    one, so that &sk_buff becomes completely private and caller is allowed
-+ *    to modify all the data of returned buffer. This means that this
-+ *    function is not recommended for use in circumstances when only
-+ *    header is going to be modified. Use pskb_copy() instead.
-+ */
-+
-+struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
-+{
-+      int headerlen = skb_headroom(skb);
-+      unsigned int size = skb_end_offset(skb) + skb->data_len;
-+      struct sk_buff *n = __alloc_skb(size, gfp_mask,
-+                                      skb_alloc_rx_flag(skb), NUMA_NO_NODE);
-+
-+      if (!n)
-+              return NULL;
-+
-+      /* Set the data pointer */
-+      skb_reserve(n, headerlen);
-+      /* Set the tail pointer and length */
-+      skb_put(n, skb->len);
-+
-+      if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len))
-+              BUG();
-+
-+      copy_skb_header(n, skb);
-+      return n;
-+}
-+EXPORT_SYMBOL(skb_copy);
-+
-+/**
-+ *    __pskb_copy     -       create copy of an sk_buff with private head.
-+ *    @skb: buffer to copy
-+ *    @headroom: headroom of new skb
-+ *    @gfp_mask: allocation priority
-+ *
-+ *    Make a copy of both an &sk_buff and part of its data, located
-+ *    in header. Fragmented data remain shared. This is used when
-+ *    the caller wishes to modify only header of &sk_buff and needs
-+ *    private copy of the header to alter. Returns %NULL on failure
-+ *    or the pointer to the buffer on success.
-+ *    The returned buffer has a reference count of 1.
-+ */
-+
-+struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask)
-+{
-+      unsigned int size = skb_headlen(skb) + headroom;
-+      struct sk_buff *n = __alloc_skb(size, gfp_mask,
-+                                      skb_alloc_rx_flag(skb), NUMA_NO_NODE);
-+
-+      if (!n)
-+              goto out;
-+
-+      /* Set the data pointer */
-+      skb_reserve(n, headroom);
-+      /* Set the tail pointer and length */
-+      skb_put(n, skb_headlen(skb));
-+      /* Copy the bytes */
-+      skb_copy_from_linear_data(skb, n->data, n->len);
-+
-+      n->truesize += skb->data_len;
-+      n->data_len  = skb->data_len;
-+      n->len       = skb->len;
-+
-+      if (skb_shinfo(skb)->nr_frags) {
-+              int i;
-+
-+              if (skb_orphan_frags(skb, gfp_mask)) {
-+                      kfree_skb(n);
-+                      n = NULL;
-+                      goto out;
-+              }
-+              for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+                      skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
-+                      skb_frag_ref(skb, i);
-+              }
-+              skb_shinfo(n)->nr_frags = i;
-+      }
-+
-+      if (skb_has_frag_list(skb)) {
-+              skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
-+              skb_clone_fraglist(n);
-+      }
-+
-+      copy_skb_header(n, skb);
-+out:
-+      return n;
-+}
-+EXPORT_SYMBOL(__pskb_copy);
-+
-+/**
-+ *    pskb_expand_head - reallocate header of &sk_buff
-+ *    @skb: buffer to reallocate
-+ *    @nhead: room to add at head
-+ *    @ntail: room to add at tail
-+ *    @gfp_mask: allocation priority
-+ *
-+ *    Expands (or creates identical copy, if &nhead and &ntail are zero)
-+ *    header of skb. &sk_buff itself is not changed. &sk_buff MUST have
-+ *    reference count of 1. Returns zero in the case of success or error,
-+ *    if expansion failed. In the last case, &sk_buff is not changed.
-+ *
-+ *    All the pointers pointing into skb header may change and must be
-+ *    reloaded after call to this function.
-+ */
-+
-+int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
-+                   gfp_t gfp_mask)
-+{
-+      int i;
-+      u8 *data;
-+      int size = nhead + skb_end_offset(skb) + ntail;
-+      long off;
-+
-+      BUG_ON(nhead < 0);
-+
-+      if (skb_shared(skb))
-+              BUG();
-+
-+      size = SKB_DATA_ALIGN(size);
-+
-+      if (skb_pfmemalloc(skb))
-+              gfp_mask |= __GFP_MEMALLOC;
-+      data = kmalloc_reserve(size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)),
-+                             gfp_mask, NUMA_NO_NODE, NULL);
-+      if (!data)
-+              goto nodata;
-+      size = SKB_WITH_OVERHEAD(ksize(data));
-+
-+      /* Copy only real data... and, alas, header. This should be
-+       * optimized for the cases when header is void.
-+       */
-+      memcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head);
-+
-+      memcpy((struct skb_shared_info *)(data + size),
-+             skb_shinfo(skb),
-+             offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
-+
-+      /*
-+       * if shinfo is shared we must drop the old head gracefully, but if it
-+       * is not we can just drop the old head and let the existing refcount
-+       * be since all we did is relocate the values
-+       */
-+      if (skb_cloned(skb)) {
-+              /* copy this zero copy skb frags */
-+              if (skb_orphan_frags(skb, gfp_mask))
-+                      goto nofrags;
-+              for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-+                      skb_frag_ref(skb, i);
-+
-+              if (skb_has_frag_list(skb))
-+                      skb_clone_fraglist(skb);
-+
-+              skb_release_data(skb);
-+      } else {
-+              skb_free_head(skb);
-+      }
-+      off = (data + nhead) - skb->head;
-+
-+      skb->head     = data;
-+      skb->head_frag = 0;
-+      skb->data    += off;
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+      skb->end      = size;
-+      off           = nhead;
-+#else
-+      skb->end      = skb->head + size;
-+#endif
-+      skb->tail             += off;
-+      skb_headers_offset_update(skb, off);
-+      /* Only adjust this if it actually is csum_start rather than csum */
-+      if (skb->ip_summed == CHECKSUM_PARTIAL)
-+              skb->csum_start += nhead;
-+      skb->cloned   = 0;
-+      skb->hdr_len  = 0;
-+      skb->nohdr    = 0;
-+      atomic_set(&skb_shinfo(skb)->dataref, 1);
-+      return 0;
-+
-+nofrags:
-+      kfree(data);
-+nodata:
-+      return -ENOMEM;
-+}
-+EXPORT_SYMBOL(pskb_expand_head);
-+
-+/* Make private copy of skb with writable head and some headroom */
-+
-+struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
-+{
-+      struct sk_buff *skb2;
-+      int delta = headroom - skb_headroom(skb);
-+
-+      if (delta <= 0)
-+              skb2 = pskb_copy(skb, GFP_ATOMIC);
-+      else {
-+              skb2 = skb_clone(skb, GFP_ATOMIC);
-+              if (skb2 && pskb_expand_head(skb2, SKB_DATA_ALIGN(delta), 0,
-+                                           GFP_ATOMIC)) {
-+                      kfree_skb(skb2);
-+                      skb2 = NULL;
-+              }
-+      }
-+      return skb2;
-+}
-+EXPORT_SYMBOL(skb_realloc_headroom);
-+
-+/**
-+ *    skb_copy_expand -       copy and expand sk_buff
-+ *    @skb: buffer to copy
-+ *    @newheadroom: new free bytes at head
-+ *    @newtailroom: new free bytes at tail
-+ *    @gfp_mask: allocation priority
-+ *
-+ *    Make a copy of both an &sk_buff and its data and while doing so
-+ *    allocate additional space.
-+ *
-+ *    This is used when the caller wishes to modify the data and needs a
-+ *    private copy of the data to alter as well as more space for new fields.
-+ *    Returns %NULL on failure or the pointer to the buffer
-+ *    on success. The returned buffer has a reference count of 1.
-+ *
-+ *    You must pass %GFP_ATOMIC as the allocation priority if this function
-+ *    is called from an interrupt.
-+ */
-+struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
-+                              int newheadroom, int newtailroom,
-+                              gfp_t gfp_mask)
-+{
-+      /*
-+       *      Allocate the copy buffer
-+       */
-+      struct sk_buff *n = __alloc_skb(newheadroom + skb->len + newtailroom,
-+                                      gfp_mask, skb_alloc_rx_flag(skb),
-+                                      NUMA_NO_NODE);
-+      int oldheadroom = skb_headroom(skb);
-+      int head_copy_len, head_copy_off;
-+      int off;
-+
-+      if (!n)
-+              return NULL;
-+
-+      skb_reserve(n, newheadroom);
-+
-+      /* Set the tail pointer and length */
-+      skb_put(n, skb->len);
-+
-+      head_copy_len = oldheadroom;
-+      head_copy_off = 0;
-+      if (newheadroom <= head_copy_len)
-+              head_copy_len = newheadroom;
-+      else
-+              head_copy_off = newheadroom - head_copy_len;
-+
-+      /* Copy the linear header and data. */
-+      if (skb_copy_bits(skb, -head_copy_len, n->head + head_copy_off,
-+                        skb->len + head_copy_len))
-+              BUG();
-+
-+      copy_skb_header(n, skb);
-+
-+      off                  = newheadroom - oldheadroom;
-+      if (n->ip_summed == CHECKSUM_PARTIAL)
-+              n->csum_start += off;
-+#ifdef NET_SKBUFF_DATA_USES_OFFSET
-+      skb_headers_offset_update(n, off);
-+#endif
-+
-+      return n;
-+}
-+EXPORT_SYMBOL(skb_copy_expand);
-+
-+/**
-+ *    skb_pad                 -       zero pad the tail of an skb
-+ *    @skb: buffer to pad
-+ *    @pad: space to pad
-+ *
-+ *    Ensure that a buffer is followed by a padding area that is zero
-+ *    filled. Used by network drivers which may DMA or transfer data
-+ *    beyond the buffer end onto the wire.
-+ *
-+ *    May return error in out of memory cases. The skb is freed on error.
-+ */
-+
-+int skb_pad(struct sk_buff *skb, int pad)
-+{
-+      int err;
-+      int ntail;
-+
-+      /* If the skbuff is non linear tailroom is always zero.. */
-+      if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) {
-+              memset(skb->data+skb->len, 0, pad);
-+              return 0;
-+      }
-+
-+      ntail = skb->data_len + pad - (skb->end - skb->tail);
-+      if (likely(skb_cloned(skb) || ntail > 0)) {
-+              err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC);
-+              if (unlikely(err))
-+                      goto free_skb;
-+      }
-+
-+      /* FIXME: The use of this function with non-linear skb's really needs
-+       * to be audited.
-+       */
-+      err = skb_linearize(skb);
-+      if (unlikely(err))
-+              goto free_skb;
-+
-+      memset(skb->data + skb->len, 0, pad);
-+      return 0;
-+
-+free_skb:
-+      kfree_skb(skb);
-+      return err;
-+}
-+EXPORT_SYMBOL(skb_pad);
-+
-+/**
-+ *    skb_put - add data to a buffer
-+ *    @skb: buffer to use
-+ *    @len: amount of data to add
-+ *
-+ *    This function extends the used data area of the buffer. If this would
-+ *    exceed the total buffer size the kernel will panic. A pointer to the
-+ *    first byte of the extra data is returned.
-+ */
-+unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
-+{
-+      unsigned char *tmp = skb_tail_pointer(skb);
-+      SKB_LINEAR_ASSERT(skb);
-+      skb->tail += len;
-+      skb->len  += len;
-+      if (unlikely(skb->tail > skb->end))
-+              skb_over_panic(skb, len, __builtin_return_address(0));
-+      return tmp;
-+}
-+EXPORT_SYMBOL(skb_put);
-+
-+/**
-+ *    skb_push - add data to the start of a buffer
-+ *    @skb: buffer to use
-+ *    @len: amount of data to add
-+ *
-+ *    This function extends the used data area of the buffer at the buffer
-+ *    start. If this would exceed the total buffer headroom the kernel will
-+ *    panic. A pointer to the first byte of the extra data is returned.
-+ */
-+unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
-+{
-+      skb->data -= len;
-+      skb->len  += len;
-+      if (unlikely(skb->data<skb->head))
-+              skb_under_panic(skb, len, __builtin_return_address(0));
-+      return skb->data;
-+}
-+EXPORT_SYMBOL(skb_push);
-+
-+/**
-+ *    skb_pull - remove data from the start of a buffer
-+ *    @skb: buffer to use
-+ *    @len: amount of data to remove
-+ *
-+ *    This function removes data from the start of a buffer, returning
-+ *    the memory to the headroom. A pointer to the next data in the buffer
-+ *    is returned. Once the data has been pulled future pushes will overwrite
-+ *    the old data.
-+ */
-+unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
-+{
-+      return skb_pull_inline(skb, len);
-+}
-+EXPORT_SYMBOL(skb_pull);
-+
-+/**
-+ *    skb_trim - remove end from a buffer
-+ *    @skb: buffer to alter
-+ *    @len: new length
-+ *
-+ *    Cut the length of a buffer down by removing data from the tail. If
-+ *    the buffer is already under the length specified it is not modified.
-+ *    The skb must be linear.
-+ */
-+void skb_trim(struct sk_buff *skb, unsigned int len)
-+{
-+      if (skb->len > len)
-+              __skb_trim(skb, len);
-+}
-+EXPORT_SYMBOL(skb_trim);
-+
-+/* Trims skb to length len. It can change skb pointers.
-+ */
-+
-+int ___pskb_trim(struct sk_buff *skb, unsigned int len)
-+{
-+      struct sk_buff **fragp;
-+      struct sk_buff *frag;
-+      int offset = skb_headlen(skb);
-+      int nfrags = skb_shinfo(skb)->nr_frags;
-+      int i;
-+      int err;
-+
-+      if (skb_cloned(skb) &&
-+          unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))))
-+              return err;
-+
-+      i = 0;
-+      if (offset >= len)
-+              goto drop_pages;
-+
-+      for (; i < nfrags; i++) {
-+              int end = offset + skb_frag_size(&skb_shinfo(skb)->frags[i]);
-+
-+              if (end < len) {
-+                      offset = end;
-+                      continue;
-+              }
-+
-+              skb_frag_size_set(&skb_shinfo(skb)->frags[i++], len - offset);
-+
-+drop_pages:
-+              skb_shinfo(skb)->nr_frags = i;
-+
-+              for (; i < nfrags; i++)
-+                      skb_frag_unref(skb, i);
-+
-+              if (skb_has_frag_list(skb))
-+                      skb_drop_fraglist(skb);
-+              goto done;
-+      }
-+
-+      for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp);
-+           fragp = &frag->next) {
-+              int end = offset + frag->len;
-+
-+              if (skb_shared(frag)) {
-+                      struct sk_buff *nfrag;
-+
-+                      nfrag = skb_clone(frag, GFP_ATOMIC);
-+                      if (unlikely(!nfrag))
-+                              return -ENOMEM;
-+
-+                      nfrag->next = frag->next;
-+                      consume_skb(frag);
-+                      frag = nfrag;
-+                      *fragp = frag;
-+              }
-+
-+              if (end < len) {
-+                      offset = end;
-+                      continue;
-+              }
-+
-+              if (end > len &&
-+                  unlikely((err = pskb_trim(frag, len - offset))))
-+                      return err;
-+
-+              if (frag->next)
-+                      skb_drop_list(&frag->next);
-+              break;
-+      }
-+
-+done:
-+      if (len > skb_headlen(skb)) {
-+              skb->data_len -= skb->len - len;
-+              skb->len       = len;
-+      } else {
-+              skb->len       = len;
-+              skb->data_len  = 0;
-+              skb_set_tail_pointer(skb, len);
-+      }
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(___pskb_trim);
-+
-+/**
-+ *    __pskb_pull_tail - advance tail of skb header
-+ *    @skb: buffer to reallocate
-+ *    @delta: number of bytes to advance tail
-+ *
-+ *    The function makes a sense only on a fragmented &sk_buff,
-+ *    it expands header moving its tail forward and copying necessary
-+ *    data from fragmented part.
-+ *
-+ *    &sk_buff MUST have reference count of 1.
-+ *
-+ *    Returns %NULL (and &sk_buff does not change) if pull failed
-+ *    or value of new tail of skb in the case of success.
-+ *
-+ *    All the pointers pointing into skb header may change and must be
-+ *    reloaded after call to this function.
-+ */
-+
-+/* Moves tail of skb head forward, copying data from fragmented part,
-+ * when it is necessary.
-+ * 1. It may fail due to malloc failure.
-+ * 2. It may change skb pointers.
-+ *
-+ * It is pretty complicated. Luckily, it is called only in exceptional cases.
-+ */
-+unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
-+{
-+      /* If skb has not enough free space at tail, get new one
-+       * plus 128 bytes for future expansions. If we have enough
-+       * room at tail, reallocate without expansion only if skb is cloned.
-+       */
-+      int i, k, eat = (skb->tail + delta) - skb->end;
-+
-+      if (eat > 0 || skb_cloned(skb)) {
-+              if (pskb_expand_head(skb, 0, eat > 0 ? eat + 128 : 0,
-+                                   GFP_ATOMIC))
-+                      return NULL;
-+      }
-+
-+      if (skb_copy_bits(skb, skb_headlen(skb), skb_tail_pointer(skb), delta))
-+              BUG();
-+
-+      /* Optimization: no fragments, no reasons to preestimate
-+       * size of pulled pages. Superb.
-+       */
-+      if (!skb_has_frag_list(skb))
-+              goto pull_pages;
-+
-+      /* Estimate size of pulled pages. */
-+      eat = delta;
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+              int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
-+
-+              if (size >= eat)
-+                      goto pull_pages;
-+              eat -= size;
-+      }
-+
-+      /* If we need update frag list, we are in troubles.
-+       * Certainly, it possible to add an offset to skb data,
-+       * but taking into account that pulling is expected to
-+       * be very rare operation, it is worth to fight against
-+       * further bloating skb head and crucify ourselves here instead.
-+       * Pure masohism, indeed. 8)8)
-+       */
-+      if (eat) {
-+              struct sk_buff *list = skb_shinfo(skb)->frag_list;
-+              struct sk_buff *clone = NULL;
-+              struct sk_buff *insp = NULL;
-+
-+              do {
-+                      BUG_ON(!list);
-+
-+                      if (list->len <= eat) {
-+                              /* Eaten as whole. */
-+                              eat -= list->len;
-+                              list = list->next;
-+                              insp = list;
-+                      } else {
-+                              /* Eaten partially. */
-+
-+                              if (skb_shared(list)) {
-+                                      /* Sucks! We need to fork list. :-( */
-+                                      clone = skb_clone(list, GFP_ATOMIC);
-+                                      if (!clone)
-+                                              return NULL;
-+                                      insp = list->next;
-+                                      list = clone;
-+                              } else {
-+                                      /* This may be pulled without
-+                                       * problems. */
-+                                      insp = list;
-+                              }
-+                              if (!pskb_pull(list, eat)) {
-+                                      kfree_skb(clone);
-+                                      return NULL;
-+                              }
-+                              break;
-+                      }
-+              } while (eat);
-+
-+              /* Free pulled out fragments. */
-+              while ((list = skb_shinfo(skb)->frag_list) != insp) {
-+                      skb_shinfo(skb)->frag_list = list->next;
-+                      kfree_skb(list);
-+              }
-+              /* And insert new clone at head. */
-+              if (clone) {
-+                      clone->next = list;
-+                      skb_shinfo(skb)->frag_list = clone;
-+              }
-+      }
-+      /* Success! Now we may commit changes to skb data. */
-+
-+pull_pages:
-+      eat = delta;
-+      k = 0;
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+              int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
-+
-+              if (size <= eat) {
-+                      skb_frag_unref(skb, i);
-+                      eat -= size;
-+              } else {
-+                      skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i];
-+                      if (eat) {
-+                              skb_shinfo(skb)->frags[k].page_offset += eat;
-+                              skb_frag_size_sub(&skb_shinfo(skb)->frags[k], eat);
-+                              eat = 0;
-+                      }
-+                      k++;
-+              }
-+      }
-+      skb_shinfo(skb)->nr_frags = k;
-+
-+      skb->tail     += delta;
-+      skb->data_len -= delta;
-+
-+      return skb_tail_pointer(skb);
-+}
-+EXPORT_SYMBOL(__pskb_pull_tail);
-+
-+/**
-+ *    skb_copy_bits - copy bits from skb to kernel buffer
-+ *    @skb: source skb
-+ *    @offset: offset in source
-+ *    @to: destination buffer
-+ *    @len: number of bytes to copy
-+ *
-+ *    Copy the specified number of bytes from the source skb to the
-+ *    destination buffer.
-+ *
-+ *    CAUTION ! :
-+ *            If its prototype is ever changed,
-+ *            check arch/{*}/net/{*}.S files,
-+ *            since it is called from BPF assembly code.
-+ */
-+int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
-+{
-+      int start = skb_headlen(skb);
-+      struct sk_buff *frag_iter;
-+      int i, copy;
-+
-+      if (offset > (int)skb->len - len)
-+              goto fault;
-+
-+      /* Copy header. */
-+      if ((copy = start - offset) > 0) {
-+              if (copy > len)
-+                      copy = len;
-+              skb_copy_from_linear_data_offset(skb, offset, to, copy);
-+              if ((len -= copy) == 0)
-+                      return 0;
-+              offset += copy;
-+              to     += copy;
-+      }
-+
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+              int end;
-+              skb_frag_t *f = &skb_shinfo(skb)->frags[i];
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + skb_frag_size(f);
-+              if ((copy = end - offset) > 0) {
-+                      u8 *vaddr;
-+
-+                      if (copy > len)
-+                              copy = len;
-+
-+                      vaddr = kmap_atomic(skb_frag_page(f));
-+                      memcpy(to,
-+                             vaddr + f->page_offset + offset - start,
-+                             copy);
-+                      kunmap_atomic(vaddr);
-+
-+                      if ((len -= copy) == 0)
-+                              return 0;
-+                      offset += copy;
-+                      to     += copy;
-+              }
-+              start = end;
-+      }
-+
-+      skb_walk_frags(skb, frag_iter) {
-+              int end;
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + frag_iter->len;
-+              if ((copy = end - offset) > 0) {
-+                      if (copy > len)
-+                              copy = len;
-+                      if (skb_copy_bits(frag_iter, offset - start, to, copy))
-+                              goto fault;
-+                      if ((len -= copy) == 0)
-+                              return 0;
-+                      offset += copy;
-+                      to     += copy;
-+              }
-+              start = end;
-+      }
-+
-+      if (!len)
-+              return 0;
-+
-+fault:
-+      return -EFAULT;
-+}
-+EXPORT_SYMBOL(skb_copy_bits);
-+
-+/*
-+ * Callback from splice_to_pipe(), if we need to release some pages
-+ * at the end of the spd in case we error'ed out in filling the pipe.
-+ */
-+static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
-+{
-+      put_page(spd->pages[i]);
-+}
-+
-+static struct page *linear_to_page(struct page *page, unsigned int *len,
-+                                 unsigned int *offset,
-+                                 struct sock *sk)
-+{
-+      struct page_frag *pfrag = sk_page_frag(sk);
-+
-+      if (!sk_page_frag_refill(sk, pfrag))
-+              return NULL;
-+
-+      *len = min_t(unsigned int, *len, pfrag->size - pfrag->offset);
-+
-+      memcpy(page_address(pfrag->page) + pfrag->offset,
-+             page_address(page) + *offset, *len);
-+      *offset = pfrag->offset;
-+      pfrag->offset += *len;
-+
-+      return pfrag->page;
-+}
-+
-+static bool spd_can_coalesce(const struct splice_pipe_desc *spd,
-+                           struct page *page,
-+                           unsigned int offset)
-+{
-+      return  spd->nr_pages &&
-+              spd->pages[spd->nr_pages - 1] == page &&
-+              (spd->partial[spd->nr_pages - 1].offset +
-+               spd->partial[spd->nr_pages - 1].len == offset);
-+}
-+
-+/*
-+ * Fill page/offset/length into spd, if it can hold more pages.
-+ */
-+static bool spd_fill_page(struct splice_pipe_desc *spd,
-+                        struct pipe_inode_info *pipe, struct page *page,
-+                        unsigned int *len, unsigned int offset,
-+                        bool linear,
-+                        struct sock *sk)
-+{
-+      if (unlikely(spd->nr_pages == MAX_SKB_FRAGS))
-+              return true;
-+
-+      if (linear) {
-+              page = linear_to_page(page, len, &offset, sk);
-+              if (!page)
-+                      return true;
-+      }
-+      if (spd_can_coalesce(spd, page, offset)) {
-+              spd->partial[spd->nr_pages - 1].len += *len;
-+              return false;
-+      }
-+      get_page(page);
-+      spd->pages[spd->nr_pages] = page;
-+      spd->partial[spd->nr_pages].len = *len;
-+      spd->partial[spd->nr_pages].offset = offset;
-+      spd->nr_pages++;
-+
-+      return false;
-+}
-+
-+static bool __splice_segment(struct page *page, unsigned int poff,
-+                           unsigned int plen, unsigned int *off,
-+                           unsigned int *len,
-+                           struct splice_pipe_desc *spd, bool linear,
-+                           struct sock *sk,
-+                           struct pipe_inode_info *pipe)
-+{
-+      if (!*len)
-+              return true;
-+
-+      /* skip this segment if already processed */
-+      if (*off >= plen) {
-+              *off -= plen;
-+              return false;
-+      }
-+
-+      /* ignore any bits we already processed */
-+      poff += *off;
-+      plen -= *off;
-+      *off = 0;
-+
-+      do {
-+              unsigned int flen = min(*len, plen);
-+
-+              if (spd_fill_page(spd, pipe, page, &flen, poff,
-+                                linear, sk))
-+                      return true;
-+              poff += flen;
-+              plen -= flen;
-+              *len -= flen;
-+      } while (*len && plen);
-+
-+      return false;
-+}
-+
-+/*
-+ * Map linear and fragment data from the skb to spd. It reports true if the
-+ * pipe is full or if we already spliced the requested length.
-+ */
-+static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
-+                            unsigned int *offset, unsigned int *len,
-+                            struct splice_pipe_desc *spd, struct sock *sk)
-+{
-+      int seg;
-+
-+      /* map the linear part :
-+       * If skb->head_frag is set, this 'linear' part is backed by a
-+       * fragment, and if the head is not shared with any clones then
-+       * we can avoid a copy since we own the head portion of this page.
-+       */
-+      if (__splice_segment(virt_to_page(skb->data),
-+                           (unsigned long) skb->data & (PAGE_SIZE - 1),
-+                           skb_headlen(skb),
-+                           offset, len, spd,
-+                           skb_head_is_locked(skb),
-+                           sk, pipe))
-+              return true;
-+
-+      /*
-+       * then map the fragments
-+       */
-+      for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) {
-+              const skb_frag_t *f = &skb_shinfo(skb)->frags[seg];
-+
-+              if (__splice_segment(skb_frag_page(f),
-+                                   f->page_offset, skb_frag_size(f),
-+                                   offset, len, spd, false, sk, pipe))
-+                      return true;
-+      }
-+
-+      return false;
-+}
-+
-+/*
-+ * Map data from the skb to a pipe. Should handle both the linear part,
-+ * the fragments, and the frag list. It does NOT handle frag lists within
-+ * the frag list, if such a thing exists. We'd probably need to recurse to
-+ * handle that cleanly.
-+ */
-+int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
-+                  struct pipe_inode_info *pipe, unsigned int tlen,
-+                  unsigned int flags)
-+{
-+      struct partial_page partial[MAX_SKB_FRAGS];
-+      struct page *pages[MAX_SKB_FRAGS];
-+      struct splice_pipe_desc spd = {
-+              .pages = pages,
-+              .partial = partial,
-+              .nr_pages_max = MAX_SKB_FRAGS,
-+              .flags = flags,
-+              .ops = &sock_pipe_buf_ops,
-+              .spd_release = sock_spd_release,
-+      };
-+      struct sk_buff *frag_iter;
-+      struct sock *sk = skb->sk;
-+      int ret = 0;
-+
-+      /*
-+       * __skb_splice_bits() only fails if the output has no room left,
-+       * so no point in going over the frag_list for the error case.
-+       */
-+      if (__skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk))
-+              goto done;
-+      else if (!tlen)
-+              goto done;
-+
-+      /*
-+       * now see if we have a frag_list to map
-+       */
-+      skb_walk_frags(skb, frag_iter) {
-+              if (!tlen)
-+                      break;
-+              if (__skb_splice_bits(frag_iter, pipe, &offset, &tlen, &spd, sk))
-+                      break;
-+      }
-+
-+done:
-+      if (spd.nr_pages) {
-+              /*
-+               * Drop the socket lock, otherwise we have reverse
-+               * locking dependencies between sk_lock and i_mutex
-+               * here as compared to sendfile(). We enter here
-+               * with the socket lock held, and splice_to_pipe() will
-+               * grab the pipe inode lock. For sendfile() emulation,
-+               * we call into ->sendpage() with the i_mutex lock held
-+               * and networking will grab the socket lock.
-+               */
-+              release_sock(sk);
-+              ret = splice_to_pipe(pipe, &spd);
-+              lock_sock(sk);
-+      }
-+
-+      return ret;
-+}
-+
-+/**
-+ *    skb_store_bits - store bits from kernel buffer to skb
-+ *    @skb: destination buffer
-+ *    @offset: offset in destination
-+ *    @from: source buffer
-+ *    @len: number of bytes to copy
-+ *
-+ *    Copy the specified number of bytes from the source buffer to the
-+ *    destination skb.  This function handles all the messy bits of
-+ *    traversing fragment lists and such.
-+ */
-+
-+int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
-+{
-+      int start = skb_headlen(skb);
-+      struct sk_buff *frag_iter;
-+      int i, copy;
-+
-+      if (offset > (int)skb->len - len)
-+              goto fault;
-+
-+      if ((copy = start - offset) > 0) {
-+              if (copy > len)
-+                      copy = len;
-+              skb_copy_to_linear_data_offset(skb, offset, from, copy);
-+              if ((len -= copy) == 0)
-+                      return 0;
-+              offset += copy;
-+              from += copy;
-+      }
-+
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+              skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-+              int end;
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + skb_frag_size(frag);
-+              if ((copy = end - offset) > 0) {
-+                      u8 *vaddr;
-+
-+                      if (copy > len)
-+                              copy = len;
-+
-+                      vaddr = kmap_atomic(skb_frag_page(frag));
-+                      memcpy(vaddr + frag->page_offset + offset - start,
-+                             from, copy);
-+                      kunmap_atomic(vaddr);
-+
-+                      if ((len -= copy) == 0)
-+                              return 0;
-+                      offset += copy;
-+                      from += copy;
-+              }
-+              start = end;
-+      }
-+
-+      skb_walk_frags(skb, frag_iter) {
-+              int end;
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + frag_iter->len;
-+              if ((copy = end - offset) > 0) {
-+                      if (copy > len)
-+                              copy = len;
-+                      if (skb_store_bits(frag_iter, offset - start,
-+                                         from, copy))
-+                              goto fault;
-+                      if ((len -= copy) == 0)
-+                              return 0;
-+                      offset += copy;
-+                      from += copy;
-+              }
-+              start = end;
-+      }
-+      if (!len)
-+              return 0;
-+
-+fault:
-+      return -EFAULT;
-+}
-+EXPORT_SYMBOL(skb_store_bits);
-+
-+/* Checksum skb data. */
-+
-+__wsum skb_checksum(const struct sk_buff *skb, int offset,
-+                        int len, __wsum csum)
-+{
-+      int start = skb_headlen(skb);
-+      int i, copy = start - offset;
-+      struct sk_buff *frag_iter;
-+      int pos = 0;
-+
-+      /* Checksum header. */
-+      if (copy > 0) {
-+              if (copy > len)
-+                      copy = len;
-+              csum = csum_partial(skb->data + offset, copy, csum);
-+              if ((len -= copy) == 0)
-+                      return csum;
-+              offset += copy;
-+              pos     = copy;
-+      }
-+
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+              int end;
-+              skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + skb_frag_size(frag);
-+              if ((copy = end - offset) > 0) {
-+                      __wsum csum2;
-+                      u8 *vaddr;
-+
-+                      if (copy > len)
-+                              copy = len;
-+                      vaddr = kmap_atomic(skb_frag_page(frag));
-+                      csum2 = csum_partial(vaddr + frag->page_offset +
-+                                           offset - start, copy, 0);
-+                      kunmap_atomic(vaddr);
-+                      csum = csum_block_add(csum, csum2, pos);
-+                      if (!(len -= copy))
-+                              return csum;
-+                      offset += copy;
-+                      pos    += copy;
-+              }
-+              start = end;
-+      }
-+
-+      skb_walk_frags(skb, frag_iter) {
-+              int end;
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + frag_iter->len;
-+              if ((copy = end - offset) > 0) {
-+                      __wsum csum2;
-+                      if (copy > len)
-+                              copy = len;
-+                      csum2 = skb_checksum(frag_iter, offset - start,
-+                                           copy, 0);
-+                      csum = csum_block_add(csum, csum2, pos);
-+                      if ((len -= copy) == 0)
-+                              return csum;
-+                      offset += copy;
-+                      pos    += copy;
-+              }
-+              start = end;
-+      }
-+      BUG_ON(len);
-+
-+      return csum;
-+}
-+EXPORT_SYMBOL(skb_checksum);
-+
-+/* Both of above in one bottle. */
-+
-+__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
-+                                  u8 *to, int len, __wsum csum)
-+{
-+      int start = skb_headlen(skb);
-+      int i, copy = start - offset;
-+      struct sk_buff *frag_iter;
-+      int pos = 0;
-+
-+      /* Copy header. */
-+      if (copy > 0) {
-+              if (copy > len)
-+                      copy = len;
-+              csum = csum_partial_copy_nocheck(skb->data + offset, to,
-+                                               copy, csum);
-+              if ((len -= copy) == 0)
-+                      return csum;
-+              offset += copy;
-+              to     += copy;
-+              pos     = copy;
-+      }
-+
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+              int end;
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
-+              if ((copy = end - offset) > 0) {
-+                      __wsum csum2;
-+                      u8 *vaddr;
-+                      skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-+
-+                      if (copy > len)
-+                              copy = len;
-+                      vaddr = kmap_atomic(skb_frag_page(frag));
-+                      csum2 = csum_partial_copy_nocheck(vaddr +
-+                                                        frag->page_offset +
-+                                                        offset - start, to,
-+                                                        copy, 0);
-+                      kunmap_atomic(vaddr);
-+                      csum = csum_block_add(csum, csum2, pos);
-+                      if (!(len -= copy))
-+                              return csum;
-+                      offset += copy;
-+                      to     += copy;
-+                      pos    += copy;
-+              }
-+              start = end;
-+      }
-+
-+      skb_walk_frags(skb, frag_iter) {
-+              __wsum csum2;
-+              int end;
-+
-+              WARN_ON(start > offset + len);
-+
-+              end = start + frag_iter->len;
-+              if ((copy = end - offset) > 0) {
-+                      if (copy > len)
-+                              copy = len;
-+                      csum2 = skb_copy_and_csum_bits(frag_iter,
-+                                                     offset - start,
-+                                                     to, copy, 0);
-+                      csum = csum_block_add(csum, csum2, pos);
-+                      if ((len -= copy) == 0)
-+                              return csum;
-+                      offset += copy;
-+                      to     += copy;
-+                      pos    += copy;
-+              }
-+              start = end;
-+      }
-+      BUG_ON(len);
-+      return csum;
-+}
-+EXPORT_SYMBOL(skb_copy_and_csum_bits);
-+
-+void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
-+{
-+      __wsum csum;
-+      long csstart;
-+
-+      if (skb->ip_summed == CHECKSUM_PARTIAL)
-+              csstart = skb_checksum_start_offset(skb);
-+      else
-+              csstart = skb_headlen(skb);
-+
-+      BUG_ON(csstart > skb_headlen(skb));
-+
-+      skb_copy_from_linear_data(skb, to, csstart);
-+
-+      csum = 0;
-+      if (csstart != skb->len)
-+              csum = skb_copy_and_csum_bits(skb, csstart, to + csstart,
-+                                            skb->len - csstart, 0);
-+
-+      if (skb->ip_summed == CHECKSUM_PARTIAL) {
-+              long csstuff = csstart + skb->csum_offset;
-+
-+              *((__sum16 *)(to + csstuff)) = csum_fold(csum);
-+      }
-+}
-+EXPORT_SYMBOL(skb_copy_and_csum_dev);
-+
-+/**
-+ *    skb_dequeue - remove from the head of the queue
-+ *    @list: list to dequeue from
-+ *
-+ *    Remove the head of the list. The list lock is taken so the function
-+ *    may be used safely with other locking list functions. The head item is
-+ *    returned or %NULL if the list is empty.
-+ */
-+
-+struct sk_buff *skb_dequeue(struct sk_buff_head *list)
-+{
-+      unsigned long flags;
-+      struct sk_buff *result;
-+
-+      spin_lock_irqsave(&list->lock, flags);
-+      result = __skb_dequeue(list);
-+      spin_unlock_irqrestore(&list->lock, flags);
-+      return result;
-+}
-+EXPORT_SYMBOL(skb_dequeue);
-+
-+/**
-+ *    skb_dequeue_tail - remove from the tail of the queue
-+ *    @list: list to dequeue from
-+ *
-+ *    Remove the tail of the list. The list lock is taken so the function
-+ *    may be used safely with other locking list functions. The tail item is
-+ *    returned or %NULL if the list is empty.
-+ */
-+struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
-+{
-+      unsigned long flags;
-+      struct sk_buff *result;
-+
-+      spin_lock_irqsave(&list->lock, flags);
-+      result = __skb_dequeue_tail(list);
-+      spin_unlock_irqrestore(&list->lock, flags);
-+      return result;
-+}
-+EXPORT_SYMBOL(skb_dequeue_tail);
-+
-+/**
-+ *    skb_queue_purge - empty a list
-+ *    @list: list to empty
-+ *
-+ *    Delete all buffers on an &sk_buff list. Each buffer is removed from
-+ *    the list and one reference dropped. This function takes the list
-+ *    lock and is atomic with respect to other list locking functions.
-+ */
-+void skb_queue_purge(struct sk_buff_head *list)
-+{
-+      struct sk_buff *skb;
-+      while ((skb = skb_dequeue(list)) != NULL)
-+              kfree_skb(skb);
-+}
-+EXPORT_SYMBOL(skb_queue_purge);
-+
-+/**
-+ *    skb_queue_head - queue a buffer at the list head
-+ *    @list: list to use
-+ *    @newsk: buffer to queue
-+ *
-+ *    Queue a buffer at the start of the list. This function takes the
-+ *    list lock and can be used safely with other locking &sk_buff functions
-+ *    safely.
-+ *
-+ *    A buffer cannot be placed on two lists at the same time.
-+ */
-+void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
-+{
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&list->lock, flags);
-+      __skb_queue_head(list, newsk);
-+      spin_unlock_irqrestore(&list->lock, flags);
-+}
-+EXPORT_SYMBOL(skb_queue_head);
-+
-+/**
-+ *    skb_queue_tail - queue a buffer at the list tail
-+ *    @list: list to use
-+ *    @newsk: buffer to queue
-+ *
-+ *    Queue a buffer at the tail of the list. This function takes the
-+ *    list lock and can be used safely with other locking &sk_buff functions
-+ *    safely.
-+ *
-+ *    A buffer cannot be placed on two lists at the same time.
-+ */
-+void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
-+{
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&list->lock, flags);
-+      __skb_queue_tail(list, newsk);
-+      spin_unlock_irqrestore(&list->lock, flags);
-+}
-+EXPORT_SYMBOL(skb_queue_tail);
-+
-+/**
-+ *    skb_unlink      -       remove a buffer from a list
-+ *    @skb: buffer to remove
-+ *    @list: list to use
-+ *
-+ *    Remove a packet from a list. The list locks are taken and this
-+ *    function is atomic with respect to other list locked calls
-+ *
-+ *    You must know what list the SKB is on.
-+ */
-+void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
-+{
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&list->lock, flags);
-+      __skb_unlink(skb, list);
-+      spin_unlock_irqrestore(&list->lock, flags);
-+}
-+EXPORT_SYMBOL(skb_unlink);
-+
-+/**
-+ *    skb_append      -       append a buffer
-+ *    @old: buffer to insert after
-+ *    @newsk: buffer to insert
-+ *    @list: list to use
-+ *
-+ *    Place a packet after a given packet in a list. The list locks are taken
-+ *    and this function is atomic with respect to other list locked calls.
-+ *    A buffer cannot be placed on two lists at the same time.
-+ */
-+void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list)
-+{
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&list->lock, flags);
-+      __skb_queue_after(list, old, newsk);
-+      spin_unlock_irqrestore(&list->lock, flags);
-+}
-+EXPORT_SYMBOL(skb_append);
-+
-+/**
-+ *    skb_insert      -       insert a buffer
-+ *    @old: buffer to insert before
-+ *    @newsk: buffer to insert
-+ *    @list: list to use
-+ *
-+ *    Place a packet before a given packet in a list. The list locks are
-+ *    taken and this function is atomic with respect to other list locked
-+ *    calls.
-+ *
-+ *    A buffer cannot be placed on two lists at the same time.
-+ */
-+void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list)
-+{
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&list->lock, flags);
-+      __skb_insert(newsk, old->prev, old, list);
-+      spin_unlock_irqrestore(&list->lock, flags);
-+}
-+EXPORT_SYMBOL(skb_insert);
-+
-+static inline void skb_split_inside_header(struct sk_buff *skb,
-+                                         struct sk_buff* skb1,
-+                                         const u32 len, const int pos)
-+{
-+      int i;
-+
-+      skb_copy_from_linear_data_offset(skb, len, skb_put(skb1, pos - len),
-+                                       pos - len);
-+      /* And move data appendix as is. */
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-+              skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i];
-+
-+      skb_shinfo(skb1)->nr_frags = skb_shinfo(skb)->nr_frags;
-+      skb_shinfo(skb)->nr_frags  = 0;
-+      skb1->data_len             = skb->data_len;
-+      skb1->len                  += skb1->data_len;
-+      skb->data_len              = 0;
-+      skb->len                   = len;
-+      skb_set_tail_pointer(skb, len);
-+}
-+
-+static inline void skb_split_no_header(struct sk_buff *skb,
-+                                     struct sk_buff* skb1,
-+                                     const u32 len, int pos)
-+{
-+      int i, k = 0;
-+      const int nfrags = skb_shinfo(skb)->nr_frags;
-+
-+      skb_shinfo(skb)->nr_frags = 0;
-+      skb1->len                 = skb1->data_len = skb->len - len;
-+      skb->len                  = len;
-+      skb->data_len             = len - pos;
-+
-+      for (i = 0; i < nfrags; i++) {
-+              int size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
-+
-+              if (pos + size > len) {
-+                      skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i];
-+
-+                      if (pos < len) {
-+                              /* Split frag.
-+                               * We have two variants in this case:
-+                               * 1. Move all the frag to the second
-+                               *    part, if it is possible. F.e.
-+                               *    this approach is mandatory for TUX,
-+                               *    where splitting is expensive.
-+                               * 2. Split is accurately. We make this.
-+                               */
-+                              skb_frag_ref(skb, i);
-+                              skb_shinfo(skb1)->frags[0].page_offset += len - pos;
-+                              skb_frag_size_sub(&skb_shinfo(skb1)->frags[0], len - pos);
-+                              skb_frag_size_set(&skb_shinfo(skb)->frags[i], len - pos);
-+                              skb_shinfo(skb)->nr_frags++;
-+                      }
-+                      k++;
-+              } else
-+                      skb_shinfo(skb)->nr_frags++;
-+              pos += size;
-+      }
-+      skb_shinfo(skb1)->nr_frags = k;
-+}
-+
-+/**
-+ * skb_split - Split fragmented skb to two parts at length len.
-+ * @skb: the buffer to split
-+ * @skb1: the buffer to receive the second part
-+ * @len: new length for skb
-+ */
-+void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
-+{
-+      int pos = skb_headlen(skb);
-+
-+      skb_shinfo(skb1)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
-+      if (len < pos)  /* Split line is inside header. */
-+              skb_split_inside_header(skb, skb1, len, pos);
-+      else            /* Second chunk has no header, nothing to copy. */
-+              skb_split_no_header(skb, skb1, len, pos);
-+}
-+EXPORT_SYMBOL(skb_split);
-+
-+/* Shifting from/to a cloned skb is a no-go.
-+ *
-+ * Caller cannot keep skb_shinfo related pointers past calling here!
-+ */
-+static int skb_prepare_for_shift(struct sk_buff *skb)
-+{
-+      return skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-+}
-+
-+/**
-+ * skb_shift - Shifts paged data partially from skb to another
-+ * @tgt: buffer into which tail data gets added
-+ * @skb: buffer from which the paged data comes from
-+ * @shiftlen: shift up to this many bytes
-+ *
-+ * Attempts to shift up to shiftlen worth of bytes, which may be less than
-+ * the length of the skb, from skb to tgt. Returns number bytes shifted.
-+ * It's up to caller to free skb if everything was shifted.
-+ *
-+ * If @tgt runs out of frags, the whole operation is aborted.
-+ *
-+ * Skb cannot include anything else but paged data while tgt is allowed
-+ * to have non-paged data as well.
-+ *
-+ * TODO: full sized shift could be optimized but that would need
-+ * specialized skb free'er to handle frags without up-to-date nr_frags.
-+ */
-+int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
-+{
-+      int from, to, merge, todo;
-+      struct skb_frag_struct *fragfrom, *fragto;
-+
-+      BUG_ON(shiftlen > skb->len);
-+      BUG_ON(skb_headlen(skb));       /* Would corrupt stream */
-+
-+      todo = shiftlen;
-+      from = 0;
-+      to = skb_shinfo(tgt)->nr_frags;
-+      fragfrom = &skb_shinfo(skb)->frags[from];
-+
-+      /* Actual merge is delayed until the point when we know we can
-+       * commit all, so that we don't have to undo partial changes
-+       */
-+      if (!to ||
-+          !skb_can_coalesce(tgt, to, skb_frag_page(fragfrom),
-+                            fragfrom->page_offset)) {
-+              merge = -1;
-+      } else {
-+              merge = to - 1;
-+
-+              todo -= skb_frag_size(fragfrom);
-+              if (todo < 0) {
-+                      if (skb_prepare_for_shift(skb) ||
-+                          skb_prepare_for_shift(tgt))
-+                              return 0;
-+
-+                      /* All previous frag pointers might be stale! */
-+                      fragfrom = &skb_shinfo(skb)->frags[from];
-+                      fragto = &skb_shinfo(tgt)->frags[merge];
-+
-+                      skb_frag_size_add(fragto, shiftlen);
-+                      skb_frag_size_sub(fragfrom, shiftlen);
-+                      fragfrom->page_offset += shiftlen;
-+
-+                      goto onlymerged;
-+              }
-+
-+              from++;
-+      }
-+
-+      /* Skip full, not-fitting skb to avoid expensive operations */
-+      if ((shiftlen == skb->len) &&
-+          (skb_shinfo(skb)->nr_frags - from) > (MAX_SKB_FRAGS - to))
-+              return 0;
-+
-+      if (skb_prepare_for_shift(skb) || skb_prepare_for_shift(tgt))
-+              return 0;
-+
-+      while ((todo > 0) && (from < skb_shinfo(skb)->nr_frags)) {
-+              if (to == MAX_SKB_FRAGS)
-+                      return 0;
-+
-+              fragfrom = &skb_shinfo(skb)->frags[from];
-+              fragto = &skb_shinfo(tgt)->frags[to];
-+
-+              if (todo >= skb_frag_size(fragfrom)) {
-+                      *fragto = *fragfrom;
-+                      todo -= skb_frag_size(fragfrom);
-+                      from++;
-+                      to++;
-+
-+              } else {
-+                      __skb_frag_ref(fragfrom);
-+                      fragto->page = fragfrom->page;
-+                      fragto->page_offset = fragfrom->page_offset;
-+                      skb_frag_size_set(fragto, todo);
-+
-+                      fragfrom->page_offset += todo;
-+                      skb_frag_size_sub(fragfrom, todo);
-+                      todo = 0;
-+
-+                      to++;
-+                      break;
-+              }
-+      }
-+
-+      /* Ready to "commit" this state change to tgt */
-+      skb_shinfo(tgt)->nr_frags = to;
-+
-+      if (merge >= 0) {
-+              fragfrom = &skb_shinfo(skb)->frags[0];
-+              fragto = &skb_shinfo(tgt)->frags[merge];
-+
-+              skb_frag_size_add(fragto, skb_frag_size(fragfrom));
-+              __skb_frag_unref(fragfrom);
-+      }
-+
-+      /* Reposition in the original skb */
-+      to = 0;
-+      while (from < skb_shinfo(skb)->nr_frags)
-+              skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++];
-+      skb_shinfo(skb)->nr_frags = to;
-+
-+      BUG_ON(todo > 0 && !skb_shinfo(skb)->nr_frags);
-+
-+onlymerged:
-+      /* Most likely the tgt won't ever need its checksum anymore, skb on
-+       * the other hand might need it if it needs to be resent
-+       */
-+      tgt->ip_summed = CHECKSUM_PARTIAL;
-+      skb->ip_summed = CHECKSUM_PARTIAL;
-+
-+      /* Yak, is it really working this way? Some helper please? */
-+      skb->len -= shiftlen;
-+      skb->data_len -= shiftlen;
-+      skb->truesize -= shiftlen;
-+      tgt->len += shiftlen;
-+      tgt->data_len += shiftlen;
-+      tgt->truesize += shiftlen;
-+
-+      return shiftlen;
-+}
-+
-+/**
-+ * skb_prepare_seq_read - Prepare a sequential read of skb data
-+ * @skb: the buffer to read
-+ * @from: lower offset of data to be read
-+ * @to: upper offset of data to be read
-+ * @st: state variable
-+ *
-+ * Initializes the specified state variable. Must be called before
-+ * invoking skb_seq_read() for the first time.
-+ */
-+void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
-+                        unsigned int to, struct skb_seq_state *st)
-+{
-+      st->lower_offset = from;
-+      st->upper_offset = to;
-+      st->root_skb = st->cur_skb = skb;
-+      st->frag_idx = st->stepped_offset = 0;
-+      st->frag_data = NULL;
-+}
-+EXPORT_SYMBOL(skb_prepare_seq_read);
-+
-+/**
-+ * skb_seq_read - Sequentially read skb data
-+ * @consumed: number of bytes consumed by the caller so far
-+ * @data: destination pointer for data to be returned
-+ * @st: state variable
-+ *
-+ * Reads a block of skb data at &consumed relative to the
-+ * lower offset specified to skb_prepare_seq_read(). Assigns
-+ * the head of the data block to &data and returns the length
-+ * of the block or 0 if the end of the skb data or the upper
-+ * offset has been reached.
-+ *
-+ * The caller is not required to consume all of the data
-+ * returned, i.e. &consumed is typically set to the number
-+ * of bytes already consumed and the next call to
-+ * skb_seq_read() will return the remaining part of the block.
-+ *
-+ * Note 1: The size of each block of data returned can be arbitrary,
-+ *       this limitation is the cost for zerocopy seqeuental
-+ *       reads of potentially non linear data.
-+ *
-+ * Note 2: Fragment lists within fragments are not implemented
-+ *       at the moment, state->root_skb could be replaced with
-+ *       a stack for this purpose.
-+ */
-+unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
-+                        struct skb_seq_state *st)
-+{
-+      unsigned int block_limit, abs_offset = consumed + st->lower_offset;
-+      skb_frag_t *frag;
-+
-+      if (unlikely(abs_offset >= st->upper_offset))
-+              return 0;
-+
-+next_skb:
-+      block_limit = skb_headlen(st->cur_skb) + st->stepped_offset;
-+
-+      if (abs_offset < block_limit && !st->frag_data) {
-+              *data = st->cur_skb->data + (abs_offset - st->stepped_offset);
-+              return block_limit - abs_offset;
-+      }
-+
-+      if (st->frag_idx == 0 && !st->frag_data)
-+              st->stepped_offset += skb_headlen(st->cur_skb);
-+
-+      while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) {
-+              frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx];
-+              block_limit = skb_frag_size(frag) + st->stepped_offset;
-+
-+              if (abs_offset < block_limit) {
-+                      if (!st->frag_data)
-+                              st->frag_data = kmap_atomic(skb_frag_page(frag));
-+
-+                      *data = (u8 *) st->frag_data + frag->page_offset +
-+                              (abs_offset - st->stepped_offset);
-+
-+                      return block_limit - abs_offset;
-+              }
-+
-+              if (st->frag_data) {
-+                      kunmap_atomic(st->frag_data);
-+                      st->frag_data = NULL;
-+              }
-+
-+              st->frag_idx++;
-+              st->stepped_offset += skb_frag_size(frag);
-+      }
-+
-+      if (st->frag_data) {
-+              kunmap_atomic(st->frag_data);
-+              st->frag_data = NULL;
-+      }
-+
-+      if (st->root_skb == st->cur_skb && skb_has_frag_list(st->root_skb)) {
-+              st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
-+              st->frag_idx = 0;
-+              goto next_skb;
-+      } else if (st->cur_skb->next) {
-+              st->cur_skb = st->cur_skb->next;
-+              st->frag_idx = 0;
-+              goto next_skb;
-+      }
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(skb_seq_read);
-+
-+/**
-+ * skb_abort_seq_read - Abort a sequential read of skb data
-+ * @st: state variable
-+ *
-+ * Must be called if skb_seq_read() was not called until it
-+ * returned 0.
-+ */
-+void skb_abort_seq_read(struct skb_seq_state *st)
-+{
-+      if (st->frag_data)
-+              kunmap_atomic(st->frag_data);
-+}
-+EXPORT_SYMBOL(skb_abort_seq_read);
-+
-+#define TS_SKB_CB(state)      ((struct skb_seq_state *) &((state)->cb))
-+
-+static