summary'>refs'>log'>tree'>commit'>diffstats
diff options
context:
space:
mode:
authorBertrand Jacquin <bertrand@jacquin.bzh>2019-05-10 22:46:45 +0100
committerBertrand Jacquin <bertrand@jacquin.bzh>2019-05-11 14:12:04 +0100
commit'>621812c1cd2e464ead8e5ed6f1e8d95bef0851d8 ( ('>patch)
tree'>924e3ae9ece71cab9f4d661119b2c791daba265e
parentsys-kernel/stable-sources: Add 5.0 (diff)
downloadetc-portage-patches-621812c1cd2e464ead8e5ed6f1e8d95bef0851d8.tar.gz
sys-kernel/stable-sources: Add 5.1.1
-rw-rw-r--r--sys-kernel/boest-v5.1.1/0001-patch-5.1-ja1.diff.patch2120
--rw-r--r--'>sys-kernel/boest-v5.1.1/0002-pool-2.6.25-tcp-timewait-20s.diff.patch2727
--rw-r--r--sys-kernel/boest-v5.1.1/0003-pool-2.6.25-disable-tcp-debug.diff.patch2525
--rw-r--r--r--sys-kernel/boest-v5.1.1/0004-TCP-add-a-sysctl-to-disable-simultaneous-connection-.patch142
--rw-r--r--r--sys-kernel/boest-v5.1.1/0005-pool-2.6.25-disable-kbdrate-at-boot.diff.patch34
--rw-r--r--r--sys-kernel/boest-v5.1.1/0006-Disable-CONFIG_PROCESSOR_SELECT-printk-s.patch45
--rw-r--r--'>sys-kernel/boest-v5.1.1/0007-This-patch-adds-support-for-a-restricted-user-contro.patch7575
--rw-r--r--r--sys-kernel/boest-v5.1.1/0008-fs-Enable-link-security-restrictions-by-default.patch26
--rw-r--r--r--'>sys-kernel/boest-v5.1.1/0009-usb-storage-Disable-UAS-on-JMicron-SATA-enclosure.patch3737
--rw-r--r--r--sys-kernel/boest-v5.1.1/0010-5.1-2600_enable-key-swapping-for-apple-mac.patch.patch125
--rw-r--r--r--sys-kernel/boest-v5.1.1/0011-5.1-4567_distro-Gentoo-Kconfig.patch.patch173
-rw-rw-r--r--sys-kernel/boest-v5.1.1/0012-WARNING.patch565
--rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0001-arm-partially-revert-702b94bff3c50542a6e4ab9a4f4cef0.patch107
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0002-Revert-rtc-pcf8523-properly-handle-oscillator-stop-b.patch58
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0003-smsx95xx-fix-crimes-against-truesize.patch49
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0004-smsc95xx-Experimental-Enable-turbo_mode-and-packetsi.patch45
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0005-Allow-mac-address-to-be-set-in-smsc95xx.patch98
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0006-Protect-__release_resource-against-resources-without.patch30
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0007-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch29
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0008-irq-bcm2836-Avoid-Invalid-trigger-warning.patch26
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0009-irqchip-bcm2835-Add-FIQ-support.patch131
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0010-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch101
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0011-spi-spidev-Completely-disable-the-spidev-warning.patch26
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0012-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch105
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0013-firmware-Updated-mailbox-header.patch29
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0014-rtc-Add-SPI-alias-for-pcf2123-driver.patch22
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0015-watchdog-bcm2835-Support-setting-reboot-partition.patch104
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0016-reboot-Use-power-off-rather-than-busy-spinning-when-.patch25
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0017-bcm-Make-RASPBERRYPI_POWER-depend-on-PM.patch21
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0018-Register-the-clocks-early-during-the-boot-process-so.patch47
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0019-bcm2835-rng-Avoid-initialising-if-already-enabled.patch27
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0020-clk-bcm2835-Mark-used-PLLs-and-dividers-CRITICAL.patch30
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0021-clk-bcm2835-Add-claim-clocks-property.patch104
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0022-clk-bcm2835-Read-max-core-clock-from-firmware.patch117
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0023-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch40
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0024-sound-Demote-deferral-errors-to-INFO-level.patch37
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0025-Update-vfpmodule.c.patch139
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0026-i2c-bcm2835-Add-debug-support.patch191
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0027-mm-Remove-the-PFN-busy-warning.patch27
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0028-ASoC-Add-prompt-for-ICS43432-codec.patch27
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0029-irqchip-irq-bcm2836-Remove-regmap-and-syscon-use.patch116
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0030-lan78xx-Enable-LEDs-and-auto-negotiation.patch50
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0031-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch31
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0032-amba_pl011-Round-input-clock-up.patch88
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0033-amba_pl011-Insert-mb-for-correct-FIFO-handling.patch29
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0034-amba_pl011-Add-cts-event-workaround-DT-property.patch54
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0035-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch24
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0036-Main-bcm2708-bcm2709-linux-port.patch158
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0037-Add-dwc_otg-driver.patch61396
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0038-bcm2708-framebuffer-driver.patch3578
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0039-fbdev-add-FBIOCOPYAREA-ioctl.patch336
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0040-Speed-up-console-framebuffer-imageblit-function.patch211
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0041-dmaengine-Add-support-for-BCM2708.patch648
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0042-MMC-added-alternative-MMC-driver.patch1984
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0043-Adding-bcm2835-sdhost-driver-and-an-overlay-to-enabl.patch2490
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0044-vc_mem-Add-vc_mem-driver-for-querying-firmware-memor.patch523
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0045-vcsm-VideoCore-shared-memory-service-for-BCM2835.patch4995
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0046-Add-dev-gpiomem-device-for-rootless-user-GPIO-access.patch309
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0047-Add-SMI-driver.patch1948
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0048-MISC-bcm2835-smi-use-clock-manager-and-fix-reload-is.patch171
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0049-Add-SMI-NAND-driver.patch356
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0050-Revert-Add-SMI-NAND-driver.patch356
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0051-Add-cpufreq-driver.patch265
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0052-Add-Chris-Boot-s-i2c-driver.patch666
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0053-char-broadcom-Add-vcio-module.patch226
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0054-firmware-bcm2835-Support-ARCH_BCM270x.patch85
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0055-scripts-Add-mkknlimg-and-knlinfo-scripts-from-tools-.patch537
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0056-BCM2708-Add-core-Device-Tree-support.patch18104
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0057-BCM270x_DT-Add-pwr_led-and-the-required-input-trigge.patch179
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0058-Added-Device-IDs-for-August-DVB-T-205.patch24
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0059-Improve-__copy_to_user-and-__copy_from_user-performa.patch1575
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0060-gpio-poweroff-Allow-it-to-work-on-Raspberry-Pi.patch37
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0061-mfd-Add-Raspberry-Pi-Sense-HAT-core-driver.patch865
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0062-ASoC-Add-support-for-Rpi-DAC.patch129
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0063-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch294
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0064-Added-support-for-HiFiBerry-DAC.patch601
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0065-Added-driver-for-HiFiBerry-Amp-amplifier-add-on-boar.patch655
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0066-Add-driver-for-rpi-proto.patch170
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0067-Add-Support-for-JustBoom-Audio-boards.patch175
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0068-New-AudioInjector.net-Pi-soundcard-with-low-jitter-a.patch209
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0069-New-driver-for-RRA-DigiDAC1-soundcard-using-WM8741-W.patch432
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0070-Add-support-for-Dion-Audio-LOCO-DAC-AMP-HAT.patch133
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0071-Allo-Piano-DAC-boards-Initial-2-channel-stereo-suppo.patch159
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0072-Add-support-for-Allo-Piano-DAC-2.1-plus-add-on-board.patch1073
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0073-Add-support-for-Allo-Boss-DAC-add-on-board-for-Raspb.patch673
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0074-Support-for-Blokas-Labs-pisound-board.patch1280
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0075-ASoC-Add-driver-for-Cirrus-Logic-Audio-Card.patch1050
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0076-sound-Support-for-Dion-Audio-LOCO-V2-DAC-AMP-HAT.patch140
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0077-Add-support-for-Fe-Pi-audio-sound-card.-1867.patch172
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0078-Add-support-for-the-AudioInjector.net-Octo-sound-car.patch376
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0079-Driver-support-for-Google-voiceHAT-soundcard.patch256
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0080-Driver-and-overlay-for-Allo-Katana-DAC.patch410
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0081-ASoC-Add-generic-RPI-driver-for-simple-soundcards.patch302
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0082-ASoC-Add-Kconfig-and-Makefile-for-sound-soc-bcm.patch268
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0083-ASoC-Create-a-generic-Pi-Hat-WM8804-driver.patch461
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0084-rpi_display-add-backlight-driver-and-overlay.patch178
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0085-bcm2835-virtgpio-Virtual-GPIO-driver.patch262
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0086-net-Add-non-mainline-source-for-rtl8192cu-wlan.patch172985
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0087-OF-DT-Overlay-configfs-interface.patch435
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0088-brcm-adds-support-for-BCM43341-wifi.patch134
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0089-hci_h5-Don-t-send-conf_req-when-ACTIVE.patch25
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0090-config-Add-default-configs.patch2777
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0091-Add-arm64-configuration-and-device-tree-differences..patch1358
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0092-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch345
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0093-ARM64-Round-Robin-dispatch-IRQs-between-CPUs.patch76
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0094-ARM64-Force-hardware-emulation-of-deprecated-instruc.patch30
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0095-build-arm64-Add-rules-for-.dtbo-files-for-dts-overla.patch38
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0096-Revert-build-arm64-Add-rules-for-.dtbo-files-for-dts.patch38
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0097-cache-export-clean-and-invalidate.patch57
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0098-AXI-performance-monitor-driver-2222.patch687
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0099-mcp2515-Use-DT-supplied-interrupt-flags.patch38
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0100-cgroup-Disable-cgroup-memory-by-default.patch72
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0101-ARM-bcm2835-Set-Serial-number-and-Revision.patch65
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0102-dwc-otg-FIQ-Fix-bad-mode-in-data-abort-handler.patch118
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0103-ARM-Activate-FIQs-to-avoid-__irq_startup-warnings.patch38
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0104-serial-8250-bcm2835aux-suppress-EPROBE_DEFER.patch24
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0105-raspberrypi-firmware-Export-the-general-transaction-.patch34
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0106-drm-vc4-Add-a-mode-for-using-the-closed-firmware-for.patch772
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0107-drm-vc4-Name-the-primary-and-cursor-planes-in-fkms.patch26
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0108-drm-vc4-Add-DRM_DEBUG_ATOMIC-for-the-insides-of-fkms.patch72
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0109-drm-vc4-Fix-sending-of-page-flip-completion-events-i.patch44
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0110-drm-vc4-Add-support-for-setting-DPMS-in-firmwarekms.patch105
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0111-drm-vc4-Add-FB-modifier-support-to-firmwarekms.patch34
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0112-drm-vc4-Add-missing-enable-disable-vblank-handlers-i.patch83
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0113-vc4_fkms-Apply-firmware-overscan-offset-to-hardware-.patch59
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0114-drm-vc4-Fix-warning-about-vblank-interrupts-before-D.patch52
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0115-drm-vc4-Skip-SET_CURSOR_INFO-when-the-cursor-content.patch59
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0116-drm-vc4-Remove-duplicate-primary-cursor-fields-from-.patch73
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0117-vc4_firmware_kms-fix-build.patch61
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0118-gpu-vc4-fkms-Update-driver-to-not-use-plane-crtc.patch3838
--rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0119-drm-vc4-Don-t-wait-for-vblank-on-fkms-cursor-updates.patch30
--rw-r--r--r--sys-kernel/boest-v5.1.1/raspberrypi/0120-i2c-gpio-Also-set-bus-numbers-from-reg-property.patch37
--rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0121-added-capture_clear-option-to-pps-gpio-via-dtoverlay.patch24
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0122-lan78xx-Read-initial-EEE-status-from-DT.patch42
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0123-hid-Reduce-default-mouse-polling-interval-to-60Hz.patch34
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0124-Add-ability-to-export-gpio-used-by-gpio-poweroff.patch61
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0125-firmware-raspberrypi-Notify-firmware-of-a-reboot.patch86
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0126-irqchip-irq-bcm2835-Calc.-FIQ_START-at-boot-time.patch68
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0127-of-configfs-Use-of_overlay_fdt_apply-API-call.patch116
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0128-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch58
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0129-brcmfmac-Re-enable-firmware-roaming-support.patch31
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0130-lan78xx-Move-enabling-of-EEE-into-PHY-init-code.patch66
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0131-Add-rpi-poe-fan-driver.patch587
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0132-cxd2880-CXD2880_SPI_DRV-should-select-DVB_CXD2880-wi.patch22
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0133-vchiq_2835_arm-Implement-a-DMA-pool-for-small-bulk-t.patch126
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0134-hwmon-raspberrypi-Prevent-voltage-low-warnings-from-.patch77
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0135-firmware-raspberrypi-Add-backward-compatible-get_thr.patch81
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0136-sc16is7xx-Don-t-spin-if-no-data-received.patch25
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0137-drivers-thermal-step_wise-add-support-for-hysteresis.patch96
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0138-drivers-thermal-step_wise-avoid-throttling-at-hyster.patch24
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0139-Update-issue-templates-2736.patch49
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0140-gpiolib-Don-t-prevent-IRQ-usage-of-output-GPIOs.patch50
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0141-lan78xx-disable-interrupts-for-PHY-irqs.patch28
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0142-rpi-wm8804-soundcard-drop-PWRDN-register-writes.patch130
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0143-rpi-wm8804-soundcard-configure-wm8804-clocks-only-on.patch48
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0144-net-lan78xx-Support-auto-downshift-to-100Mb-s.patch97
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0145-ASoC-add-driver-for-3Dlab-Nano-soundcard-2758.patch425
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0146-staging-bcm2835-camera-Ensure-H264-header-bytes-get-.patch91
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0147-staging-bcm2835-camera-Check-the-error-for-REPEAT_SE.patch33
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0148-firmware-raspberrypi-Report-the-fw-variant-during-pr.patch83
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0149-firmware-raspberrypi-Report-the-fw-git-hash-during-p.patch62
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0150-arm64-dts-broadcom-Enable-fixups-for-overlays.patch25
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0151-bcm2835_smi-re-add-dereference-to-fix-DMA-transfers.patch22
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0152-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch46
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0153-ASoC-Add-support-for-AudioSense-Pi-add-on-soundcard.patch326
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0154-spi-spi-bcm2835-Re-enable-HW-CS.patch82
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0155-spi-spi-bcm2835-Disable-forced-software-CS.patch56
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0156-Added-driver-for-the-HiFiBerry-DAC-ADC-2694.patch464
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0157-mfd-Add-rpi_sense_core-of-compatible-string.patch28
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0158-configs-Enable-the-AD193x-codecs.patch30
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0159-lan78xx-EEE-support-is-now-a-PHY-property.patch28
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0160-Revert-staging-vchiq-delete-vchiq_killable.h.patch136
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0161-Revert-staging-vchiq_2835_arm-quit-using-custom-down.patch24
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0162-Revert-staging-vchiq-switch-to-wait_for_completion_k.patch234
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0163-Revert-staging-vchiq-rework-remove_event-handling.patch217
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0164-Revert-staging-bcm2835-audio-Drop-DT-dependency.patch98
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0165-gpu-vc4_firmware_kms-Fix-up-64-bit-compile-warnings.patch68
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0166-bcm2835-dma-Add-support-for-per-channel-flags.patch50
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0167-drm-vc4-Programming-the-CTM-is-conditional-on-runnin.patch28
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0168-rtc-rv3028-Add-backup-switchover-mode-support.patch52
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0169-ASoC-tlv320aic32x4-Break-out-clock-setting-into-sepa.patch66
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0170-ASoC-tlv320aic32x4-Properly-Set-Processing-Blocks.patch113
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0171-ASoC-tlv320aic32x4-Model-PLL-in-CCF.patch887
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0172-ASoC-tlv320aic32x4-Model-CODEC_CLKIN-in-CCF.patch124
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0173-ASoC-tlv320aic32x4-Model-DAC-ADC-dividers-in-CCF.patch312
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0174-ASoC-tlv320aic32x4-Model-BDIV-divider-in-CCF.patch214
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0175-ASoC-tlv320aic32x4-Control-clock-gating-with-CCF.patch111
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0176-ASoC-tlv320aic32x4-Move-aosr-and-dosr-setting-to-sep.patch61
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0177-ASoC-tlv320aic32x4-Dynamically-Determine-Clocking.patch289
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0178-ASoC-tlv320aic32x4-Restructure-set_dai_sysclk.patch53
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0179-ASoC-tlv320aic32x4-Remove-mclk-references.patch41
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0180-ASoC-tlv320aic32x4-Allow-192000-Sample-Rate.patch29
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0181-ASoC-tlv320aic32x4-Only-enable-with-common-clock.patch45
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0182-Audiophonics-I-Sabre-9038Q2M-DAC-driver.patch704
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0183-ASoC-tlv320aic32x4-Update-copyright-and-use-SPDX-ide.patch74
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0184-ASoC-tlv320aic32x4-Add-Switch-for-Setting-Common-Mod.patch42
-rw-r--r--sys-kernel/boest-v5.1.1/raspberrypi/0185-ASoC-tlv320aic32x4-Add-Playback-PowerTune-Controls.patch56
l---------sys-kernel/stable-sources-5.1.11
198 files changed, 306333 insertions, 0 deletions
diff --git a/sys-kernel/boest-v5.1.1/0001-patch-5.1-ja1.diff.patch b/sys-kernel/boest-v5.1.1/0001-patch-5.1-ja1.diff.patch
new file mode 100644
index 00000000..89aac1b5
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0001-patch-5.1-ja1.diff.patch
@@ -0,0 +1,2120 @@
+From c13eff2e1132816773f4184216427946ca5f238d Mon Sep 17 00:00:00 2001
+From: Julian Anastasov <ja@ssi.bg>
+Date: Mon, 6 May 2019 12:45:11 +0000
+Subject: [PATCH 01/12] patch-5.1-ja1.diff
+
+Jumbo patch containing the following parts:
+ - routes-2.X.*.diff (static_routes, alt_routes, nf_reroute but without arp_prefsrc functionality, it is replaced by arprules and rp_filter_mask)
+ - hidden-2.X.*.diff (conf/*/hidden)
+ - arprules-2.X.*.diff (iparp/arprules support)
+ - rp_filter_mask-2.X.*.diff (conf/*/rp_filter_mask)
+ - forward_shared-2.X.*.diff (conf/*/forward_shared)
+ - send-to-self-2.X.*.diff (conf/*/loop, included March 3, 2004, up to Linux 3.5)
+
+URL: http://ja.ssi.bg/patch-5.1-ja1.diff
+---
+ Documentation/networking/ip-sysctl.txt | 30 ++
+ include/linux/inetdevice.h | 3 +
+ include/net/flow.h | 2 +
+ include/net/ip_fib.h | 5 +-
+ include/net/netfilter/nf_nat.h | 5 +
+ include/net/route.h | 5 +
+ include/uapi/linux/ip.h | 3 +
+ include/uapi/linux/rtnetlink.h | 64 ++-
+ net/bridge/br_netfilter_hooks.c | 3 +
+ net/ipv4/arp.c | 695 ++++++++++++++++++++++++-
+ net/ipv4/devinet.c | 14 +-
+ net/ipv4/fib_frontend.c | 56 +-
+ net/ipv4/fib_rules.c | 5 +
+ net/ipv4/fib_semantics.c | 257 ++++++---
+ net/ipv4/fib_trie.c | 3 +
+ net/ipv4/netfilter/iptable_nat.c | 7 +
+ net/ipv4/route.c | 69 ++-
+ net/netfilter/nf_nat_core.c | 43 ++
+ net/netfilter/nf_nat_masquerade.c | 27 +-
+ security/selinux/nlmsgtab.c | 5 +-
+ 20 files changed, 1173 insertions(+), 128 deletions(-)
+
+diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
+index c4ac35234f05..5a5d64e4daf5 100644
+--- a/Documentation/networking/ip-sysctl.txt
++++ b/Documentation/networking/ip-sysctl.txt
+@@ -1077,6 +1077,19 @@ forwarding - BOOLEAN
+ Enable IP forwarding on this interface. This controls whether packets
+ received _on_ this interface can be forwarded.
+
++forward_shared - BOOLEAN
++ Integer value determines if a source validation should allow
++ forwarding of packets with local source address. 1 means yes,
++ 0 means no. By default the flag is disabled and such packets
++ are not forwarded.
++
++ If you enable this flag on internal network, the router will forward
++ packets from internal hosts with shared IP addresses no matter how
++ the rp_filter is set. This flag is activated only if it is
++ enabled both in specific device section and in "all" section.
++
++ The forward_shared value could be ignored when rp_filter is set to 0.
++
+ mc_forwarding - BOOLEAN
+ Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
+ and a multicast routing daemon is required.
+@@ -1192,6 +1205,15 @@ rp_filter - INTEGER
+ Default value is 0. Note that some distributions enable it
+ in startup scripts.
+
++rp_filter_mask - INTEGER
++ Integer value representing bitmask of the mediums for which the
++ reverse path protection is disabled. If the source validation
++ results in reverse path to interface with medium_id value in
++ the 1..31 range the access is allowed if the corresponding bit
++ is set in the bitmask. The bitmask value is considered only when
++ rp_filter is enabled. By default the bitmask is empty preserving
++ the original rp_filter semantic.
++
+ arp_filter - BOOLEAN
+ 1 - Allows you to have multiple network interfaces on the same
+ subnet, and have the ARPs for each interface be answered
+@@ -1332,6 +1354,14 @@ drop_gratuitous_arp - BOOLEAN
+ Default: off (0)
+
+
++hidden - BOOLEAN
++ Hide addresses attached to this device from other devices.
++ Such addresses will never be selected by source address autoselection
++ mechanism, host does not answer broadcast ARP requests for them,
++ does not announce them as source address of ARP requests, but they
++ are still reachable via IP. This flag is activated only if it is
++ enabled both in specific device section and in "all" section.
++
+ tag - INTEGER
+ Allows you to write a number, which can be used as required.
+ Default value is 0.
+diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
+index a64f21a97369..f2103b9e67de 100644
+--- a/include/linux/inetdevice.h
++++ b/include/linux/inetdevice.h
+@@ -97,9 +97,11 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
+ #define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING)
+ #define IN_DEV_BFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), BC_FORWARDING)
+ #define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER)
++#define IN_DEV_RPFILTER_MASK(in_dev) IN_DEV_CONF_GET(in_dev, RP_FILTER_MASK)
+ #define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK)
+ #define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \
+ ACCEPT_SOURCE_ROUTE)
++#define IN_DEV_FORWARD_SHARED(in_dev) IN_DEV_ANDCONF((in_dev), FORWARD_SHARED)
+ #define IN_DEV_ACCEPT_LOCAL(in_dev) IN_DEV_ORCONF((in_dev), ACCEPT_LOCAL)
+ #define IN_DEV_BOOTP_RELAY(in_dev) IN_DEV_ANDCONF((in_dev), BOOTP_RELAY)
+
+@@ -112,6 +114,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
+ SECURE_REDIRECTS)
+ #define IN_DEV_IDTAG(in_dev) IN_DEV_CONF_GET(in_dev, TAG)
+ #define IN_DEV_MEDIUM_ID(in_dev) IN_DEV_CONF_GET(in_dev, MEDIUM_ID)
++#define IN_DEV_HIDDEN(in_dev) IN_DEV_ANDCONF((in_dev), HIDDEN)
+ #define IN_DEV_PROMOTE_SECONDARIES(in_dev) \
+ IN_DEV_ORCONF((in_dev), \
+ PROMOTE_SECONDARIES)
+diff --git a/include/net/flow.h b/include/net/flow.h
+index a50fb77a0b27..7dcdb9b3162e 100644
+--- a/include/net/flow.h
++++ b/include/net/flow.h
+@@ -93,6 +93,7 @@ struct flowi4 {
+ #define fl4_ipsec_spi uli.spi
+ #define fl4_mh_type uli.mht.type
+ #define fl4_gre_key uli.gre_key
++ __be32 fl4_gw;
+ } __attribute__((__aligned__(BITS_PER_LONG/8)));
+
+ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
+@@ -116,6 +117,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
+ fl4->saddr = saddr;
+ fl4->fl4_dport = dport;
+ fl4->fl4_sport = sport;
++ fl4->fl4_gw = 0;
+ }
+
+ /* Reset some input parameters after previous lookup */
+diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
+index 9c8214d2116d..a1b2aa38264b 100644
+--- a/include/net/ip_fib.h
++++ b/include/net/ip_fib.h
+@@ -378,6 +378,8 @@ static inline bool fib4_rules_early_flow_dissect(struct net *net,
+ return true;
+ }
+
++u32 fib_result_table(struct fib_result *res);
++
+ #endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+ /* Exported by fib_frontend.c */
+@@ -387,7 +389,8 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb);
+ bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev);
+ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ u8 tos, int oif, struct net_device *dev,
+- struct in_device *idev, u32 *itag);
++ struct in_device *idev, u32 *itag, int our);
++void fib_select_default(const struct flowi4 *flp, struct fib_result *res);
+ #ifdef CONFIG_IP_ROUTE_CLASSID
+ static inline int fib_num_tclassid_users(struct net *net)
+ {
+diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
+index cf332c4e0b32..420836188d8a 100644
+--- a/include/net/netfilter/nf_nat.h
++++ b/include/net/netfilter/nf_nat.h
+@@ -36,6 +36,11 @@ struct nf_conn_nat {
+ #endif
+ };
+
++/* Call input routing for SNAT-ed traffic */
++unsigned int ip_nat_route_input(void *priv,
++ struct sk_buff *skb,
++ const struct nf_hook_state *state);
++
+ /* Set up the info structure to map into this range. */
+ unsigned int nf_nat_setup_info(struct nf_conn *ct,
+ const struct nf_nat_range2 *range,
+diff --git a/include/net/route.h b/include/net/route.h
+index 9883dc82f723..a617bc7e0d8f 100644
+--- a/include/net/route.h
++++ b/include/net/route.h
+@@ -182,6 +182,9 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src,
+ int ip_route_input_rcu(struct sk_buff *skb, __be32 dst, __be32 src,
+ u8 tos, struct net_device *devin,
+ struct fib_result *res);
++int ip_route_input_common_rcu(struct sk_buff *skb, __be32 dst, __be32 src,
++ u8 tos, struct net_device *devin, __be32 lsrc,
++ struct fib_result *res);
+
+ static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
+ u8 tos, struct net_device *devin)
+@@ -217,6 +220,8 @@ unsigned int inet_addr_type_dev_table(struct net *net,
+ void ip_rt_multicast_event(struct in_device *);
+ int ip_rt_ioctl(struct net *, unsigned int cmd, struct rtentry *rt);
+ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
++int ip_route_input_lookup(struct sk_buff*, __be32 dst, __be32 src, u8 tos,
++ struct net_device *devin, __be32 lsrc);
+ struct rtable *rt_dst_alloc(struct net_device *dev,
+ unsigned int flags, u16 type,
+ bool nopolicy, bool noxfrm, bool will_cache);
+diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
+index e42d13b55cf3..d03711046f2e 100644
+--- a/include/uapi/linux/ip.h
++++ b/include/uapi/linux/ip.h
+@@ -169,6 +169,9 @@ enum
+ IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
+ IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
+ IPV4_DEVCONF_BC_FORWARDING,
++ IPV4_DEVCONF_HIDDEN,
++ IPV4_DEVCONF_RP_FILTER_MASK,
++ IPV4_DEVCONF_FORWARD_SHARED,
+ __IPV4_DEVCONF_MAX
+ };
+
+diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
+index 46399367627f..92593fd1a055 100644
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -157,6 +157,13 @@ enum {
+ RTM_GETCHAIN,
+ #define RTM_GETCHAIN RTM_GETCHAIN
+
++ RTM_NEWARPRULE = 104,
++#define RTM_NEWARPRULE RTM_NEWARPRULE
++ RTM_DELARPRULE,
++#define RTM_DELARPRULE RTM_DELARPRULE
++ RTM_GETARPRULE,
++#define RTM_GETARPRULE RTM_GETARPRULE
++
+ __RTM_MAX,
+ #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
+ };
+@@ -374,8 +381,11 @@ struct rtnexthop {
+ #define RTNH_F_OFFLOAD 8 /* offloaded route */
+ #define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */
+ #define RTNH_F_UNRESOLVED 32 /* The entry is unresolved (ipmr) */
++#define RTNH_F_SUSPECT 64 /* We don't know the real state */
++#define RTNH_F_BADSTATE (RTNH_F_DEAD | RTNH_F_SUSPECT)
+
+-#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD)
++#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | \
++ RTNH_F_OFFLOAD | RTNH_F_SUSPECT)
+
+ /* Macros to handle hexthops */
+
+@@ -617,6 +627,54 @@ enum {
+
+ #define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1)
+
++/******************************************************************************
++ * Definitions used in ARP tables administration
++ ****/
++
++#define ARPA_TABLE_INPUT 0
++#define ARPA_TABLE_OUTPUT 1
++#define ARPA_TABLE_FORWARD 2
++#define ARPA_TABLE_ALL -1
++
++#define ARPM_F_PREFSRC 0x0001
++#define ARPM_F_WILDIIF 0x0002
++#define ARPM_F_WILDOIF 0x0004
++#define ARPM_F_BROADCAST 0x0008
++#define ARPM_F_UNICAST 0x0010
++
++struct arpmsg
++{
++ unsigned char arpm_family;
++ unsigned char arpm_table;
++ unsigned char arpm_action;
++ unsigned char arpm_from_len;
++ unsigned char arpm_to_len;
++ unsigned char arpm__pad1;
++ unsigned short arpm__pad2;
++ unsigned arpm_pref;
++ unsigned arpm_flags;
++};
++
++enum
++{
++ ARPA_UNSPEC,
++ ARPA_FROM, /* FROM IP prefix */
++ ARPA_TO, /* TO IP prefix */
++ ARPA_LLFROM, /* FROM LL prefix */
++ ARPA_LLTO, /* TO LL prefix */
++ ARPA_LLSRC, /* New SRC lladdr */
++ ARPA_LLDST, /* New DST lladdr */
++ ARPA_IIF, /* In interface prefix */
++ ARPA_OIF, /* Out interface prefix */
++ ARPA_SRC, /* New IP SRC */
++ ARPA_DST, /* New IP DST, not used */
++ ARPA_PACKETS, /* Packets */
++};
++++
++#define ARPA_MAX ARPA_PACKETS
++
++#define ARPA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct arpmsg))))
++
+ #ifndef __KERNEL__
+ /* RTnetlink multicast groups - backwards compatibility for userspace */
+ #define RTMGRP_LINK 1
+@@ -637,6 +695,8 @@ enum {
+ #define RTMGRP_DECnet_IFADDR 0x1000
+ #define RTMGRP_DECnet_ROUTE 0x4000
+ +
++#define RTMGRP_ARP 0x00010000
++
+ #define RTMGRP_IPV6_PREFIX 0x20000
+ #endif
+ +
+@@ -704,6 +764,8 @@ enum rtnetlink_groups {
+ #define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R
+ RTNLGRP_IPV6_MROUTE_R,
+ #define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R
++ RTNLGRP_ARP,
++#define RTNLGRP_ARP RTNLGRP_ARP
+ __RTNLGRP_MAX
+ };
+ #define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
+diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
+index 22afa566cbce..3de2da264fc8 100644
+--- a/net/bridge/br_netfilter_hooks.c
++++ b/net/bridge/br_netfilter_hooks.c
+@@ -347,6 +347,9 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_
+
+ nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
+
++ /* Old skb->dst is not expected, it is lost in all cases */
++ skb_dst_drop(skb);
++
+ if (nf_bridge->pkt_otherhost) {
+ skb->pkt_type = PACKET_OTHERHOST;
+ nf_bridge->pkt_otherhost = false;
+diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
+index 850a6f13a082..d92ae82268de 100644
+--- a/net/ipv4/arp.c
++++ b/net/ipv4/arp.c
+@@ -71,6 +71,9 @@
+ * sending (e.g. insert 8021q tag).
+ * Harald Welte : convert to make use of jenkins hash
+ * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support.
++ * Julian Anastasov: "hidden" flag: hide the
++ * interface and don't reply for it
++ * Julian Anastasov: ARP filtering via netlink
+ */
+
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+@@ -95,6 +98,7 @@
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+ #include <linux/stat.h>
++#include <net/netlink.h>
+ #include <linux/init.h>
+ #include <linux/net.h>
+ #include <linux/rcupdate.h>
+@@ -185,6 +189,48 @@ struct neigh_table arp_tbl = {
+ };
+ EXPORT_SYMBOL(arp_tbl);
+
++struct arpf_node {
++ struct arpf_node * at_next;
++ u32 at_pref;
++ u32 at_from;
++ u32 at_from_mask;
++ u32 at_to;
++ u32 at_to_mask;
++ u32 at_src;
++ atomic_t at_packets;
++ atomic_t at_refcnt;
++ unsigned at_flags;
++ unsigned char at_from_len;
++ unsigned char at_to_len;
++ unsigned char at_action;
++ char at_dead;
++ unsigned char at_llfrom_len;
++ unsigned char at_llto_len;
++ unsigned char at_llsrc_len;
++ unsigned char at_lldst_len;
++ unsigned char at_iif_len;
++ unsigned char at_oif_len;
++ unsigned short at__pad1;
++ unsigned char at_llfrom[MAX_ADDR_LEN];
++ unsigned char at_llto[MAX_ADDR_LEN];
++ unsigned char at_llsrc[MAX_ADDR_LEN];
++ unsigned char at_lldst[MAX_ADDR_LEN];
++ char at_iif[IFNAMSIZ];
++ char at_oif[IFNAMSIZ];
++};
++
++static struct arpf_node *arp_tabs[3];
++
++static struct kmem_cache *arpf_cachep;
++
++static DEFINE_RWLOCK(arpf_lock);
++
++static void
++arpf_send(int table, struct net *net, struct sk_buff *skb, u32 sip, u32 tip,
++ unsigned char *from_hw, unsigned char *to_hw,
++ struct net_device *idev, struct net_device *odev,
++ struct dst_entry *dst);
++
+ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
+ {
+ switch (dev->type) {
+@@ -338,7 +384,9 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
+ struct net_device *dev = neigh->dev;
+ __be32 target = *(__be32 *)neigh->primary_key;
+ int probes = atomic_read(&neigh->probes);
+- struct in_device *in_dev;
++ struct in_device *in_dev, *in_dev2;
++ struct net_device *dev2;
++ int mode;
+ struct dst_entry *dst = NULL;
+
+ rcu_read_lock();
+@@ -347,9 +395,22 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
+ rcu_read_unlock();
+ return;
+ }
+- switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
++ mode = IN_DEV_ARP_ANNOUNCE(in_dev);
++ if (mode != 2 && skb &&
++ (dev2 = __ip_dev_find(dev_net(dev), ip_hdr(skb)->saddr,
++ false)) != NULL &&
++ (saddr = ip_hdr(skb)->saddr,
++ in_dev2 = __in_dev_get_rcu(dev2)) != NULL &&
++ IN_DEV_HIDDEN(in_dev2)) {
++ saddr = 0;
++ goto get;
++ }
++
++ switch (mode) {
+ default:
+ case 0: /* By default announce any local IP */
++ if (saddr)
++ break;
+ if (skb && inet_addr_type_dev_table(dev_net(dev), dev,
+ ip_hdr(skb)->saddr) == RTN_LOCAL)
+ saddr = ip_hdr(skb)->saddr;
+@@ -357,9 +418,10 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
+ case 1: /* Restrict announcements of saddr in same subnet */
+ if (!skb)
+ break;
+- saddr = ip_hdr(skb)->saddr;
+- if (inet_addr_type_dev_table(dev_net(dev), dev,
+- saddr) == RTN_LOCAL) {
++ if (saddr ||
++ (saddr = ip_hdr(skb)->saddr,
++ inet_addr_type_dev_table(dev_net(dev), dev,
++ saddr) == RTN_LOCAL)) {
+ /* saddr should be known to target */
+ if (inet_addr_onlink(in_dev, target, saddr))
+ break;
+@@ -369,6 +431,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
+ case 2: /* Avoid secondary IPs, get a primary/preferred one */
+ break;
+ }
++
++get:
+ rcu_read_unlock();
+
+ if (!saddr)
+@@ -390,8 +454,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
+
+ if (skb && !(dev->priv_flags & IFF_XMIT_DST_RELEASE))
+ dst = skb_dst(skb);
+- arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
+- dst_hw, dev->dev_addr, NULL, dst);
++ arpf_send(ARPA_TABLE_OUTPUT, dev_net(dev), skb, saddr, target, NULL,
++ dst_hw, NULL, dev, dst);
+ }
+
+ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
+@@ -448,6 +512,21 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
+ return flag;
+ }
+
++static int arp_hidden(u32 tip, struct net_device *dev)
++{
++ struct net_device *dev2;
++ struct in_device *in_dev2;
++ int ret = 0;
++
++ if (!IPV4_DEVCONF_ALL(dev_net(dev), HIDDEN))
++ return 0;
++
++ if ((dev2 = __ip_dev_find(dev_net(dev), tip, false)) && dev2 != dev &&
++ (in_dev2 = __in_dev_get_rcu(dev2)) && IN_DEV_HIDDEN(in_dev2))
++ ret = 1;
++ return ret;
++}
++
+ /*
+ * Check if we can use proxy ARP for this path
+ */
+@@ -808,9 +887,10 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
+ if (sip == 0) {
+ if (arp->ar_op == htons(ARPOP_REQUEST) &&
+ inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
++ !arp_hidden(tip, dev) &&
+ !arp_ignore(in_dev, sip, tip))
+- arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,
+- sha, dev->dev_addr, sha, reply_dst);
++ arpf_send(ARPA_TABLE_INPUT, net, skb, sip, tip, sha,
++ tha, dev, NULL, reply_dst);
+ goto out_consume_skb;
+ }
+
+@@ -826,13 +906,14 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
+ dont_send = arp_ignore(in_dev, sip, tip);
+ if (!dont_send && IN_DEV_ARPFILTER(in_dev))
+ dont_send = arp_filter(sip, tip, dev);
++ if (!dont_send && skb->pkt_type != PACKET_HOST)
++ dont_send = arp_hidden(tip,dev);
+ if (!dont_send) {
+ n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
+ if (n) {
+- arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
+- sip, dev, tip, sha,
+- dev->dev_addr, sha,
+- reply_dst);
++ arpf_send(ARPA_TABLE_INPUT, net, skb,
++ sip, tip, sha, tha, dev,
++ NULL, reply_dst);
+ neigh_release(n);
+ }
+ }
+@@ -850,10 +931,9 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
+ if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
+ skb->pkt_type == PACKET_HOST ||
+ NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) {
+- arp_send_dst(ARPOP_REPLY, ETH_P_ARP,
+- sip, dev, tip, sha,
+- dev->dev_addr, sha,
+- reply_dst);
++ arpf_send(ARPA_TABLE_FORWARD, net,
++ skb, sip, tip, sha, tha, dev,
++ rt->dst.dev, reply_dst);
+ } else {
+ pneigh_enqueue(&arp_tbl,
+ in_dev->arp_parms, skb);
+@@ -1279,6 +1359,577 @@ void arp_ifdown(struct net_device *dev)
+ }
+
+
++static void arpf_destroy(struct arpf_node *afp)
++{
++ if (!afp->at_dead) {
++ printk(KERN_ERR "Destroying alive arp table node %p from %08lx\n", afp,
++ *(((unsigned long*)&afp)-1));
++ return;
++ }
++ kmem_cache_free(arpf_cachep, afp);
++}
++
++static inline void arpf_put(struct arpf_node *afp)
++{
++ if (atomic_dec_and_test(&afp->at_refcnt))
++ arpf_destroy(afp);
++}
++
++static inline struct arpf_node *
++arpf_lookup(int table, struct sk_buff *skb, u32 sip, u32 tip,
++ unsigned char *from_hw, unsigned char *to_hw,
++ struct net_device *idev, struct net_device *odev)
++{
++ int sz_iif = idev? strlen(idev->name) : 0;
++ int sz_oif = odev? strlen(odev->name) : 0;
++ int alen;
++ struct arpf_node *afp;
++
++ if (ARPA_TABLE_OUTPUT != table) {
++ alen = idev->addr_len;
++ } else {
++ if (!from_hw) from_hw = odev->dev_addr;
++ if (!to_hw) to_hw = odev->broadcast;
++ alen = odev->addr_len;
++ }
++
++ read_lock_bh(&arpf_lock);
++ for (afp = arp_tabs[table]; afp; afp = afp->at_next) {
++ if ((tip ^ afp->at_to) & afp->at_to_mask)
++ continue;
++ if ((sip ^ afp->at_from) & afp->at_from_mask)
++ continue;
++ if (afp->at_llfrom_len &&
++ (afp->at_llfrom_len > alen ||
++ memcmp(from_hw, afp->at_llfrom, afp->at_llfrom_len)))
++ continue;
++ if (afp->at_llto_len &&
++ (afp->at_llto_len > alen ||
++ memcmp(to_hw, afp->at_llto, afp->at_llto_len)))
++ continue;
++ if (afp->at_iif_len &&
++ (afp->at_iif_len > sz_iif ||
++ memcmp(afp->at_iif, idev->name, afp->at_iif_len) ||
++ (sz_iif != afp->at_iif_len &&
++ !(afp->at_flags & ARPM_F_WILDIIF))))
++ continue;
++ if (afp->at_oif_len &&
++ (afp->at_oif_len > sz_oif ||
++ memcmp(afp->at_oif, odev->name, afp->at_oif_len) ||
++ (sz_oif != afp->at_oif_len &&
++ !(afp->at_flags & ARPM_F_WILDOIF))))
++ continue;
++ if (afp->at_flags & ARPM_F_BROADCAST &&
++ skb->pkt_type == PACKET_HOST)
++ continue;
++ if (afp->at_flags & ARPM_F_UNICAST &&
++ skb->pkt_type != PACKET_HOST)
++ continue;
++ if (afp->at_llsrc_len && afp->at_llsrc_len != alen)
++ continue;
++ if (afp->at_lldst_len && afp->at_lldst_len != alen)
++ continue;
++ atomic_inc(&afp->at_refcnt);
++ atomic_inc(&afp->at_packets);
++ break;
++ }
++ read_unlock_bh(&arpf_lock);
++ return afp;
++}
++
++static void
++arpf_send(int table, struct net *net, struct sk_buff *skb, u32 sip, u32 tip,
++ unsigned char *from_hw, unsigned char *to_hw,
++ struct net_device *idev, struct net_device *odev,
++ struct dst_entry *dst)
++{
++ struct arpf_node *afp = NULL;
++
++ if (!arp_tabs[table] ||
++ !net_eq(net, &init_net) ||
++ !(afp = arpf_lookup(table, skb, sip, tip,
++ from_hw, to_hw, idev, odev))) {
++ switch (table) {
++ case ARPA_TABLE_INPUT:
++ case ARPA_TABLE_FORWARD:
++ arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, idev, tip,
++ from_hw, idev->dev_addr, from_hw, dst);
++ break;
++ case ARPA_TABLE_OUTPUT:
++ arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, tip, odev, sip,
++ to_hw, odev->dev_addr, NULL, dst);
++ break;
++ }
++ return;
++ }
++
++ /* deny? */
++ if (!afp->at_action) goto out;
++
++ switch (table) {
++ case ARPA_TABLE_INPUT:
++ case ARPA_TABLE_FORWARD:
++ arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, idev, tip,
++ afp->at_lldst_len?afp->at_lldst:from_hw,
++ afp->at_llsrc_len?afp->at_llsrc:idev->dev_addr,
++ afp->at_lldst_len?afp->at_lldst:from_hw, dst);
++ break;
++ case ARPA_TABLE_OUTPUT:
++ if (afp->at_flags & ARPM_F_PREFSRC && afp->at_src == 0) {
++ struct rtable *rt;
++ struct flowi4 fl4 = { .daddr = tip,
++ .flowi4_oif = odev->ifindex };
++
++ rt = ip_route_output_key(net, &fl4);
++ if (IS_ERR(rt))
++ break;
++ sip = fl4.saddr;
++ ip_rt_put(rt);
++ if (!sip)
++ break;
++ }
++ arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, tip, odev,
++ afp->at_src?:sip,
++ afp->at_lldst_len?afp->at_lldst:to_hw,
++ afp->at_llsrc_len?afp->at_llsrc:odev->dev_addr,
++ NULL, dst);
++ break;
++ }
++
++out:
++ arpf_put(afp);
++}
++
++static int
++arpf_fill_node(struct sk_buff *skb, u32 portid, u32 seq, unsigned flags,
++ int event, int table, struct arpf_node *afp)
++{
++ struct arpmsg *am;
++ struct nlmsghdr *nlh;
++ u32 packets = atomic_read(&afp->at_packets);
++
++ nlh = nlmsg_put(skb, portid, seq, event, sizeof(*am), 0);
++ if (nlh == NULL)
++ return -ENOBUFS;
++ nlh->nlmsg_flags = flags;
++ am = nlmsg_data(nlh);
++ am->arpm_family = AF_UNSPEC;
++ am->arpm_table = table;
++ am->arpm_action = afp->at_action;
++ am->arpm_from_len = afp->at_from_len;
++ am->arpm_to_len = afp->at_to_len;
++ am->arpm_pref = afp->at_pref;
++ am->arpm_flags = afp->at_flags;
++ if (afp->at_from_len &&
++ nla_put(skb, ARPA_FROM, 4, &afp->at_from))
++ goto nla_put_failure;
++ if (afp->at_to_len &&
++ nla_put(skb, ARPA_TO, 4, &afp->at_to))
++ goto nla_put_failure;
++ if ((afp->at_src || afp->at_flags & ARPM_F_PREFSRC) &&
++ nla_put(skb, ARPA_SRC, 4, &afp->at_src))
++ goto nla_put_failure;
++ if (afp->at_iif[0] &&
++ nla_put(skb, ARPA_IIF, sizeof(afp->at_iif), afp->at_iif))
++ goto nla_put_failure;
++ if (afp->at_oif[0] &&
++ nla_put(skb, ARPA_OIF, sizeof(afp->at_oif), afp->at_oif))
++ goto nla_put_failure;
++ if (afp->at_llfrom_len &&
++ nla_put(skb, ARPA_LLFROM, afp->at_llfrom_len, afp->at_llfrom))
++ goto nla_put_failure;
++ if (afp->at_llto_len &&
++ nla_put(skb, ARPA_LLTO, afp->at_llto_len, afp->at_llto))
++ goto nla_put_failure;
++ if (afp->at_llsrc_len &&
++ nla_put(skb, ARPA_LLSRC, afp->at_llsrc_len, afp->at_llsrc))
++ goto nla_put_failure;
++ if (afp->at_lldst_len &&
++ nla_put(skb, ARPA_LLDST, afp->at_lldst_len, afp->at_lldst))
++ goto nla_put_failure;
++ if (nla_put(skb, ARPA_PACKETS, 4, &packets))
++ goto nla_put_failure;
++ nlmsg_end(skb, nlh);
++ return 0;
++
++nla_put_failure:
++ nlmsg_cancel(skb, nlh);
++ return -EMSGSIZE;
++}
++
++static void
++arpmsg_notify(struct sk_buff *oskb, struct nlmsghdr *nlh, int table,
++ struct arpf_node *afp, int event)
++{
++ struct sk_buff *skb;
++ u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
++ int payload = sizeof(struct arpmsg) + 256;
++ int err = -ENOBUFS;
++
++ skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
++ if (!skb)
++ goto errout;
++
++ err = arpf_fill_node(skb, portid, nlh->nlmsg_seq, 0, event, table, afp);
++ if (err < 0) {
++ kfree_skb(skb);
++ goto errout;
++ }
++
++ rtnl_notify(skb, &init_net, portid, RTNLGRP_ARP, nlh, GFP_KERNEL);
++ return;
++errout:
++ if (err < 0)
++ rtnl_set_sk_err(&init_net, RTNLGRP_ARP, err);
++}
++
++static inline int
++arpf_str_size(int a, struct nlattr **rta, int maxlen)
++{
++ int size = 0;
++
++ if (rta[a] && (size = nla_len(rta[a]))) {
++ if (size > maxlen)
++ size = maxlen;
++ }
++ return size;
++}
++
++static inline int
++arpf_get_str(int a, struct nlattr **rta, unsigned char *p,
++ int maxlen, unsigned char *l)
++{
++ int size = arpf_str_size(a, rta, maxlen);
++
++ if (size) {
++ memcpy(p, nla_data(rta[a]), size);
++ *l = size;
++ }
++ return size;
++}
++
++#define ARPF_MATCH_U32(ind, field) ( \
++ (!rta[ind] && r->at_ ## field == 0) || \
++ (rta[ind] && \
++ *(u32*) nla_data(rta[ind]) == r->at_ ## field))
++
++#define ARPF_MATCH_STR(ind, field) ( \
++ (!rta[ind] && r->at_ ## field ## _len == 0) || \
++ (rta[ind] && r->at_ ## field ## _len && \
++ r->at_ ## field ## _len < nla_len(rta[ind]) && \
++ strcmp(nla_data(rta[ind]), r->at_ ## field) == 0))
++
++#define ARPF_MATCH_DATA(ind, field) ( \
++ (!rta[ind] && r->at_ ## field ## _len == 0) || \
++ (rta[ind] && r->at_ ## field ## _len && \
++ r->at_ ## field ## _len == nla_len(rta[ind]) && \
++ memcmp(nla_data(rta[ind]), &r->at_ ## field, \
++ r->at_ ## field ## _len) == 0))
++
++/* RTM_NEWARPRULE/RTM_DELARPRULE/RTM_GETARPRULE */
++
++int arpf_rule_ctl(struct sk_buff *skb, struct nlmsghdr *n,
++ struct netlink_ext_ack *extack)
++{
++ struct net *net = sock_net(skb->sk);
++ struct nlattr *rta[ARPA_MAX + 1];
++ struct arpmsg *am;
++ struct arpf_node *r, **rp, **prevp = 0, **delp = 0, *newp = 0;
++ unsigned pref = 1;
++ int size, ret;
++
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ if (!net_eq(net, &init_net))
++ return -EINVAL;
++
++ ret = nlmsg_parse(n, sizeof(struct arpmsg), rta, ARPA_MAX, NULL,
++ extack);
++ if (ret < 0)
++ return ret;
++
++ am = nlmsg_data(n);
++ ret = -EINVAL;
++ if (am->arpm_table >= sizeof(arp_tabs)/sizeof(arp_tabs[0]))
++ goto out;
++ if (!((~am->arpm_flags) & (ARPM_F_BROADCAST|ARPM_F_UNICAST)))
++ goto out;
++ if (am->arpm_action > 1)
++ goto out;
++ if (am->arpm_to_len > 32 || am->arpm_from_len > 32)
++ goto out;
++ if (am->arpm_flags & ARPM_F_WILDIIF &&
++ (!rta[ARPA_IIF] || !nla_len(rta[ARPA_IIF]) ||
++ !*(char*) nla_data(rta[ARPA_IIF])))
++ am->arpm_flags &= ~ARPM_F_WILDIIF;
++ if (am->arpm_flags & ARPM_F_WILDOIF &&
++ (!rta[ARPA_OIF] || !nla_len(rta[ARPA_OIF]) ||
++ !*(char*) nla_data(rta[ARPA_OIF])))
++ am->arpm_flags &= ~ARPM_F_WILDOIF;
++ switch (am->arpm_table) {
++ case ARPA_TABLE_INPUT:
++ if (rta[ARPA_SRC] || rta[ARPA_OIF])
++ goto out;
++ break;
++ case ARPA_TABLE_OUTPUT:
++ if (rta[ARPA_IIF])
++ goto out;
++ if (am->arpm_flags & (ARPM_F_BROADCAST|ARPM_F_UNICAST))
++ goto out;
++ break;
++ case ARPA_TABLE_FORWARD:
++ if (rta[ARPA_SRC])
++ goto out;
++ break;
++ }
++ if (rta[ARPA_SRC] && !*(u32*) nla_data(rta[ARPA_SRC]))
++ am->arpm_flags |= ARPM_F_PREFSRC;
++ else
++ am->arpm_flags &= ~ARPM_F_PREFSRC;
++
++ for (rp = &arp_tabs[am->arpm_table]; (r=*rp) != NULL; rp=&r->at_next) {
++ if (pref < r->at_pref)
++ prevp = rp;
++ if (am->arpm_pref == r->at_pref ||
++ (!am->arpm_pref &&
++ am->arpm_to_len == r->at_to_len &&
++ am->arpm_from_len == r->at_from_len &&
++ !((am->arpm_flags ^ r->at_flags) &
++ (ARPM_F_BROADCAST | ARPM_F_UNICAST |
++ ARPM_F_WILDIIF | ARPM_F_WILDOIF)) &&
++ ARPF_MATCH_U32(ARPA_TO, to) &&
++ ARPF_MATCH_U32(ARPA_FROM, from) &&
++ ARPF_MATCH_DATA(ARPA_LLFROM, llfrom) &&
++ ARPF_MATCH_DATA(ARPA_LLTO, llto) &&
++ ARPF_MATCH_STR(ARPA_IIF, iif) &&
++ ARPF_MATCH_STR(ARPA_OIF, oif) &&
++ (n->nlmsg_type != RTM_DELARPRULE ||
++ /* DEL matches more keys */
++ (am->arpm_flags == r->at_flags &&
++ am->arpm_action == r->at_action &&
++ ARPF_MATCH_U32(ARPA_SRC, src) &&
++ ARPF_MATCH_DATA(ARPA_LLSRC, llsrc) &&
++ ARPF_MATCH_DATA(ARPA_LLDST, lldst)
++ )
++ )
++ )
++ )
++ break;
++ if (am->arpm_pref && r->at_pref > am->arpm_pref) {
++ r = NULL;
++ break;
++ }
++ pref = r->at_pref+1;
++ }
++
++ /*
++ * r=NULL: *rp != NULL (stopped before next pref), pref: not valid
++ * *rp == NULL (not found), pref: ready to use
++ * r!=NULL: found, pref: not valid
++ *
++ * prevp=NULL: no free slot
++ * prevp!=NULL: free slot for rule
++ */
++
++ if (n->nlmsg_type == RTM_DELARPRULE) {
++ if (!r)
++ return -ESRCH;
++ delp = rp;
++ goto dequeue;
++ }
++
++ if (r) {
++ /* Existing rule */
++ ret = -EEXIST;
++ if (n->nlmsg_flags&NLM_F_EXCL)
++ goto out;
++
++ if (n->nlmsg_flags&NLM_F_REPLACE) {
++ pref = r->at_pref;
++ prevp = delp = rp;
++ goto replace;
++ }
++ }
++
++ if (n->nlmsg_flags&NLM_F_APPEND) {
++ if (r) {
++ pref = r->at_pref+1;
++ for (rp=&r->at_next; (r=*rp) != NULL; rp=&r->at_next) {
++ if (pref != r->at_pref)
++ break;
++ pref ++;
++ }
++ ret = -EBUSY;
++ if (!pref)
++ goto out;
++ } else if (am->arpm_pref)
++ pref = am->arpm_pref;
++ prevp = rp;
++ }
++
++ if (!(n->nlmsg_flags&NLM_F_CREATE)) {
++ ret = -ENOENT;
++ if (n->nlmsg_flags&NLM_F_EXCL || r)
++ ret = 0;
++ goto out;
++ }
++
++ if (!(n->nlmsg_flags&NLM_F_APPEND)) {
++ if (!prevp) {
++ ret = -EBUSY;
++ if (r || *rp ||
++ (!am->arpm_pref && arp_tabs[am->arpm_table]))
++ goto out;
++ prevp = rp;
++ pref = am->arpm_pref? : 99;
++ } else {
++ if (r || !am->arpm_pref) {
++ pref = (*prevp)->at_pref - 1;
++ if (am->arpm_pref && am->arpm_pref < pref)
++ pref = am->arpm_pref;
++ } else {
++ prevp = rp;
++ pref = am->arpm_pref;
++ }
++ }
++ }
++
++replace:
++
++ ret = -ENOMEM;
++ r = kmem_cache_alloc(arpf_cachep, GFP_KERNEL);
++ if (!r)
++ return ret;
++ memset(r, 0, sizeof(*r));
++
++ arpf_get_str(ARPA_LLFROM, rta, r->at_llfrom, MAX_ADDR_LEN,
++ &r->at_llfrom_len);
++ arpf_get_str(ARPA_LLTO, rta, r->at_llto, MAX_ADDR_LEN,
++ &r->at_llto_len);
++ arpf_get_str(ARPA_LLSRC, rta, r->at_llsrc, MAX_ADDR_LEN,
++ &r->at_llsrc_len);
++ arpf_get_str(ARPA_LLDST, rta, r->at_lldst, MAX_ADDR_LEN,
++ &r->at_lldst_len);
++
++ if (delp)
++ r->at_next = (*delp)->at_next;
++ else if (*prevp)
++ r->at_next = *prevp;
++
++ r->at_pref = pref;
++ r->at_from_len = am->arpm_from_len;
++ r->at_from_mask = inet_make_mask(r->at_from_len);
++ if (rta[ARPA_FROM])
++ r->at_from = *(u32*) nla_data(rta[ARPA_FROM]);
++ r->at_from &= r->at_from_mask;
++ r->at_to_len = am->arpm_to_len;
++ r->at_to_mask = inet_make_mask(r->at_to_len);
++ if (rta[ARPA_TO])
++ r->at_to = *(u32*) nla_data(rta[ARPA_TO]);
++ r->at_to &= r->at_to_mask;
++ if (rta[ARPA_SRC])
++ r->at_src = *(u32*) nla_data(rta[ARPA_SRC]);
++ if (rta[ARPA_PACKETS]) {
++ u32 packets = *(u32*) nla_data(rta[ARPA_PACKETS]);
++ atomic_set(&r->at_packets, packets);
++ }
++ atomic_set(&r->at_refcnt, 1);
++ r->at_flags = am->arpm_flags;
++ r->at_action = am->arpm_action;
++
++ if (rta[ARPA_IIF] && (size = nla_len(rta[ARPA_IIF]))) {
++ if (size >= sizeof(r->at_iif))
++ size = sizeof(r->at_iif)-1;
++ memcpy(r->at_iif, nla_data(rta[ARPA_IIF]), size);
++ r->at_iif_len = strlen(r->at_iif);
++ }
++ if (rta[ARPA_OIF] && (size = nla_len(rta[ARPA_OIF]))) {
++ if (size >= sizeof(r->at_oif))
++ size = sizeof(r->at_oif)-1;
++ memcpy(r->at_oif, nla_data(rta[ARPA_OIF]), size);
++ r->at_oif_len = strlen(r->at_oif);
++ }
++
++ newp = r;
++
++dequeue:
++
++ if (delp) {
++ r = *delp;
++ write_lock_bh(&arpf_lock);
++ if (newp) {
++ if (!rta[ARPA_PACKETS])
++ atomic_set(&newp->at_packets,
++ atomic_read(&r->at_packets));
++ *delp = newp;
++ } else {
++ *delp = r->at_next;
++ }
++ r->at_dead = 1;
++ write_unlock_bh(&arpf_lock);
++ arpmsg_notify(skb, n, am->arpm_table, r, RTM_DELARPRULE);
++ arpf_put(r);
++ prevp = 0;
++ }
++
++ if (newp) {
++ if (prevp) {
++ write_lock_bh(&arpf_lock);
++ *prevp = newp;
++ write_unlock_bh(&arpf_lock);
++ }
++ arpmsg_notify(skb, n, am->arpm_table, newp, RTM_NEWARPRULE);
++ }
++
++ ret = 0;
++
++out:
++ return ret;
++}
++
++int arpf_dump_table(int t, struct sk_buff *skb, struct netlink_callback *cb)
++{
++ int idx, ret = -1;
++ struct arpf_node *afp;
++ int s_idx = cb->args[1];
++
++ for (idx=0, afp = arp_tabs[t]; afp; afp = afp->at_next, idx++) {
++ if (idx < s_idx)
++ continue;
++ if (arpf_fill_node(skb, NETLINK_CB(cb->skb).portid,
++ cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWARPRULE, t, afp) < 0)
++ goto out;
++ }
++
++ ret = skb->len;
++
++out:
++ cb->args[1] = idx;
++
++ return ret;
++}
++
++int arpf_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
++{
++ int idx;
++ int s_idx = cb->args[0];
++
++ read_lock_bh(&arpf_lock);
++ for (idx = 0; idx < sizeof(arp_tabs)/sizeof(arp_tabs[0]); idx++) {
++ if (idx < s_idx)
++ continue;
++ if (idx > s_idx)
++ memset(&cb->args[1], 0, sizeof(cb->args)-1*sizeof(cb->args[0]));
++ if (arpf_dump_table(idx, skb, cb) < 0)
++ break;
++ }
++ read_unlock_bh(&arpf_lock);
++ cb->args[0] = idx;
++
++ return skb->len;
++}
++
+ /*
+ * Called once on startup.
+ */
+@@ -1292,6 +1943,16 @@ static int arp_proc_init(void);
+
+ void __init arp_init(void)
+ {
++ arpf_cachep = kmem_cache_create("ip_arpf_cache",
++ sizeof(struct arpf_node), 0,
++ SLAB_HWCACHE_ALIGN, NULL);
++ if (!arpf_cachep)
++ panic("IP: failed to allocate ip_arpf_cache\n");
++
++ rtnl_register(PF_UNSPEC, RTM_NEWARPRULE, arpf_rule_ctl, NULL, 0);
++ rtnl_register(PF_UNSPEC, RTM_DELARPRULE, arpf_rule_ctl, NULL, 0);
++ rtnl_register(PF_UNSPEC, RTM_GETARPRULE, NULL, arpf_dump_rules, 0);
++
+ neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl);
+
+ dev_add_pack(&arp_packet_type);
+diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
+index eb514f312e6f..3d2c6d7617cc 100644
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -1308,9 +1308,14 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
+ if (!in_dev)
+ continue;
+
+- addr = in_dev_select_addr(in_dev, scope);
+- if (addr)
+- goto out_unlock;
++ for_primary_ifa(in_dev) {
++ if (!IN_DEV_HIDDEN(in_dev) &&
++ ifa->ifa_scope != RT_SCOPE_LINK &&
++ ifa->ifa_scope <= scope) {
++ addr = ifa->ifa_local;
++ goto out_unlock;
++ }
++ } endfor_ifa(in_dev);
+ }
+ out_unlock:
+ rcu_read_unlock();
+@@ -2462,13 +2467,16 @@ static struct devinet_sysctl_table {
+ DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
+ DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
+ "accept_source_route"),
++ DEVINET_SYSCTL_RW_ENTRY(FORWARD_SHARED, "forward_shared"),
+ DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
+ DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
+ DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
+ DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
++ DEVINET_SYSCTL_RW_ENTRY(RP_FILTER_MASK, "rp_filter_mask"),
+ DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
+ DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
+ DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
++ DEVINET_SYSCTL_RW_ENTRY(HIDDEN, "hidden"),
+ DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),
+ DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
+ DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
+diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
+index ed14ec245584..1c5782a2e983 100644
+--- a/net/ipv4/fib_frontend.c
++++ b/net/ipv4/fib_frontend.c
+@@ -51,6 +51,8 @@
+
+ #ifndef CONFIG_IP_MULTIPLE_TABLES
+
++#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
++
+ static int __net_init fib4_rules_init(struct net *net)
+ {
+ struct fib_table *local_table, *main_table;
+@@ -80,6 +82,8 @@ static bool fib4_has_custom_rules(struct net *net)
+ }
+ #else
+
++#define FIB_RES_TABLE(r) (fib_result_table(r))
++
+ struct fib_table *fib_new_table(struct net *net, u32 id)
+ {
+ struct fib_table *tb, *alias = NULL;
+@@ -351,13 +355,19 @@ EXPORT_SYMBOL_GPL(fib_info_nh_uses_dev);
+ */
+ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ u8 tos, int oif, struct net_device *dev,
+- int rpf, struct in_device *idev, u32 *itag)
++ int rpf, struct in_device *idev, u32 *itag,
++ int our)
+ {
+ struct net *net = dev_net(dev);
+ struct flow_keys flkeys;
++ u32 table;
++ unsigned char prefixlen;
++ unsigned char scope;
+ int ret, no_addr;
+ struct fib_result res;
+ struct flowi4 fl4;
++ int fwdsh;
++ unsigned int rpf_mask;
+ bool dev_match;
+
+ fl4.flowi4_oif = 0;
+@@ -371,10 +381,13 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ fl4.flowi4_tun_key.tun_id = 0;
+ fl4.flowi4_flags = 0;
+ fl4.flowi4_uid = sock_net_uid(net, NULL);
++ fl4.fl4_gw = 0;
+
+ no_addr = idev->ifa_list == NULL;
+
++ fwdsh = IN_DEV_FORWARD_SHARED(idev);
+ fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
++ rpf_mask = IN_DEV_RPFILTER_MASK(idev);
+ if (!fib4_rules_early_flow_dissect(net, skb, &fl4, &flkeys)) {
+ fl4.flowi4_proto = 0;
+ fl4.fl4_sport = 0;
+@@ -383,7 +396,12 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+
+ if (fib_lookup(net, &fl4, &res, 0))
+ goto last_resort;
+- if (res.type != RTN_UNICAST &&
++ if (fwdsh) {
++ fwdsh = (res.type == RTN_LOCAL && !our);
++ if (fwdsh)
++ rpf = 0;
++ }
++ if (res.type != RTN_UNICAST && !fwdsh &&
+ (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev)))
+ goto e_inval;
+ fib_combine_itag(itag, &res);
+@@ -393,17 +411,36 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
+ return ret;
+ }
++ if (rpf_mask && rpf) {
++ int omi = 0;
++
++ idev = __in_dev_get_rcu(FIB_RES_DEV(res));
++ if (idev)
++ omi = IN_DEV_MEDIUM_ID(idev);
++ if (omi >= 1 && omi <= 31 && ((1 << omi) & rpf_mask))
++ rpf = 0;
++ }
+ if (no_addr)
+ goto last_resort;
+- if (rpf == 1)
+- goto e_rpf;
++ table = FIB_RES_TABLE(&res);
++ prefixlen = res.prefixlen;
++ scope = res.scope;
+ fl4.flowi4_oif = dev->ifindex;
++ if (fwdsh)
++ fl4.flowi4_iif = LOOPBACK_IFINDEX;
+
+ ret = 0;
+ if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) {
+- if (res.type == RTN_UNICAST)
++ if (res.type == RTN_UNICAST &&
++ ((table == FIB_RES_TABLE(&res) &&
++ res.prefixlen >= prefixlen && res.scope >= scope) ||
++ !rpf)) {
+ ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
++ return ret;
++ }
+ }
++ if (rpf == 1)
++ goto e_rpf;
+ return ret;
+
+ last_resort:
+@@ -421,7 +458,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ /* Ignore rp_filter for packets protected by IPsec. */
+ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ u8 tos, int oif, struct net_device *dev,
+- struct in_device *idev, u32 *itag)
++ struct in_device *idev, u32 *itag, int our)
+ {
+ int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
+ struct net *net = dev_net(dev);
+@@ -446,7 +483,8 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
+ }
+
+ full_check:
+- return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag);
++ return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev,
++ itag, our);
+ }
+
+ static inline __be32 sk_extract_addr(struct sockaddr *addr)
+@@ -1328,9 +1366,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
+ switch (event) {
+ case NETDEV_UP:
+ fib_add_ifaddr(ifa);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(dev, RTNH_F_DEAD);
+-#endif
+ atomic_inc(&net->ipv4.dev_addr_genid);
+ rt_cache_flush(dev_net(dev));
+ break;
+@@ -1374,9 +1410,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
+ for_ifa(in_dev) {
+ fib_add_ifaddr(ifa);
+ } endfor_ifa(in_dev);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(dev, RTNH_F_DEAD);
+-#endif
+ atomic_inc(&net->ipv4.dev_addr_genid);
+ rt_cache_flush(net);
+ break;
+diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
+index cfec3af54c8d..6ffc52a5c272 100644
+--- a/net/ipv4/fib_rules.c
++++ b/net/ipv4/fib_rules.c
+@@ -78,6 +78,11 @@ unsigned int fib4_rules_seq_read(struct net *net)
+ return fib_rules_seq_read(net, AF_INET);
+ }
+
++u32 fib_result_table(struct fib_result *res)
++{
++ return res->table ? res->table->tb_id : RT_TABLE_UNSPEC;
++}
++
+ int __fib_lookup(struct net *net, struct flowi4 *flp,
+ struct fib_result *res, unsigned int flags)
+ {
+diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
+index 8e185b5a2bf6..4bd84d2a2ddd 100644
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -53,6 +53,7 @@ static struct hlist_head *fib_info_hash;
+ static struct hlist_head *fib_info_laddrhash;
+ static unsigned int fib_info_hash_size;
+ static unsigned int fib_info_cnt;
++DEFINE_RWLOCK(fib_nhflags_lock);
+
+ #define DEVINDEX_HASHBITS 8
+ #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
+@@ -433,28 +434,71 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
+
+ static int fib_detect_death(struct fib_info *fi, int order,
+ struct fib_info **last_resort, int *last_idx,
+- int dflt)
++ int dflt, int *last_nhsel,
++ const struct flowi4 *flp)
+ {
+ struct neighbour *n;
+- int state = NUD_NONE;
++ int nhsel;
++ int state;
++ struct fib_nh * nh;
++ __be32 dst;
++ int flag, dead = 1;
+
+- n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
+- if (n) {
+- state = n->nud_state;
+- neigh_release(n);
+- } else {
+- return 0;
+- }
+- if (state == NUD_REACHABLE)
+- return 0;
+- if ((state & NUD_VALID) && order != dflt)
+- return 0;
+- if ((state & NUD_VALID) ||
+- (*last_idx < 0 && order > dflt && state != NUD_INCOMPLETE)) {
+- *last_resort = fi;
+- *last_idx = order;
++ /* change_nexthops(fi) { */
++ for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
++ if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif &&
++ !(flp->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF))
++ continue;
++ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && nh->nh_gw &&
++ nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ if (nh->nh_flags & RTNH_F_DEAD)
++ continue;
++
++ flag = 0;
++ if (nh->nh_dev->flags & IFF_NOARP) {
++ dead = 0;
++ goto setfl;
++ }
++
++ dst = nh->nh_gw;
++ if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
++ dst = flp->daddr;
++
++ state = NUD_NONE;
++ n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
++ if (n) {
++ state = n->nud_state;
++ neigh_release(n);
++ }
++ if (state == NUD_REACHABLE ||
++ ((state & NUD_VALID) && order != dflt)) {
++ dead = 0;
++ goto setfl;
++ }
++ if (!(state & NUD_VALID))
++ flag = 1;
++ if (!dead)
++ goto setfl;
++ if ((state & NUD_VALID) ||
++ (*last_idx < 0 && order >= dflt)) {
++ *last_resort = fi;
++ *last_idx = order;
++ *last_nhsel = nhsel;
++ }
++
++ setfl:
++
++ read_lock_bh(&fib_nhflags_lock);
++ if (flag)
++ nh->nh_flags |= RTNH_F_SUSPECT;
++ else
++ nh->nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
+ }
+- return 1;
++ /* } endfor_nexthops(fi) */
++
++ return dead;
+ }
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+@@ -781,6 +825,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
+ int err = 0;
+ struct net *net;
+ struct net_device *dev;
++ struct fib_info *fi = nh->nh_parent;
+
+ net = cfg->fc_nlinfo.nl_net;
+ if (nh->nh_gw) {
+@@ -800,9 +845,12 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
+ return -ENODEV;
+ }
+ if (!(dev->flags & IFF_UP)) {
+- NL_SET_ERR_MSG(extack,
+- "Nexthop device is not up");
+- return -ENETDOWN;
++ if (fi->fib_protocol != RTPROT_STATIC) {
++ NL_SET_ERR_MSG(extack,
++ "Nexthop device is not up");
++ return -ENETDOWN;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
+ }
+ addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw);
+ if (addr_type != RTN_UNICAST) {
+@@ -847,31 +895,57 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
+ err = fib_lookup(net, &fl4, &res,
+ FIB_LOOKUP_IGNORE_LINKSTATE);
+ }
++ }
++ if (err) {
++ struct in_device *in_dev;
+
+- if (err) {
++ if (err != -ENETUNREACH ||
++ fi->fib_protocol != RTPROT_STATIC) {
+ NL_SET_ERR_MSG(extack,
+ "Nexthop has invalid gateway");
+- rcu_read_unlock();
+- return err;
++ goto out;
+ }
++
++ in_dev = inetdev_by_index(net, nh->nh_oif);
++ if (in_dev == NULL ||
++ in_dev->dev->flags & IFF_UP) {
++ NL_SET_ERR_MSG(extack,
++ "Device for nexthop is not up");
++ goto out;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
++ nh->nh_scope = RT_SCOPE_LINK;
++ nh->nh_dev = in_dev->dev;
++ dev_hold(nh->nh_dev);
++ } else {
++ err = -EINVAL;
++ if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) {
++ NL_SET_ERR_MSG(extack,
++ "Nexthop has invalid gateway");
++ goto out;
++ }
++ nh->nh_scope = res.scope;
++ nh->nh_oif = FIB_RES_OIF(res);
++ nh->nh_dev = dev = FIB_RES_DEV(res);
++ if (!dev) {
++ NL_SET_ERR_MSG(extack,
++ "No egress device for nexthop gateway");
++ goto out;
++ }
++ dev_hold(dev);
++ if (!netif_carrier_ok(dev))
++ nh->nh_flags |= RTNH_F_LINKDOWN;
++ if (!(nh->nh_dev->flags & IFF_UP)) {
++ if (fi->fib_protocol != RTPROT_STATIC) {
++ err = -ENETDOWN;
++ NL_SET_ERR_MSG(extack,
++ "Device for nexthop is not up");
++ goto out;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
++ }
++ err = 0;
+ }
+- err = -EINVAL;
+- if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) {
+- NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway");
+- goto out;
+- }
+- nh->nh_scope = res.scope;
+- nh->nh_oif = FIB_RES_OIF(res);
+- nh->nh_dev = dev = FIB_RES_DEV(res);
+- if (!dev) {
+- NL_SET_ERR_MSG(extack,
+- "No egress device for nexthop gateway");
+- goto out;
+- }
+- dev_hold(dev);
+- if (!netif_carrier_ok(dev))
+- nh->nh_flags |= RTNH_F_LINKDOWN;
+- err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
+ } else {
+ struct in_device *in_dev;
+
+@@ -887,8 +961,12 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh,
+ goto out;
+ err = -ENETDOWN;
+ if (!(in_dev->dev->flags & IFF_UP)) {
+- NL_SET_ERR_MSG(extack, "Device for nexthop is not up");
+- goto out;
++ if (fi->fib_protocol != RTPROT_STATIC) {
++ NL_SET_ERR_MSG(extack,
++ "Device for nexthop is not up");
++ goto out;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
+ }
+ nh->nh_dev = in_dev->dev;
+ dev_hold(nh->nh_dev);
+@@ -1535,10 +1613,15 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force)
+ prev_fi = fi;
+ dead = 0;
+ change_nexthops(fi) {
+- if (nexthop_nh->nh_flags & RTNH_F_DEAD)
+- dead++;
+- else if (nexthop_nh->nh_dev == dev &&
+- nexthop_nh->nh_scope != scope) {
++ if (nexthop_nh->nh_flags & RTNH_F_DEAD) {
++ if (fi->fib_protocol != RTPROT_STATIC ||
++ nexthop_nh->nh_dev == NULL ||
++ __in_dev_get_rtnl(nexthop_nh->nh_dev) == NULL ||
++ nexthop_nh->nh_dev->flags&IFF_UP)
++ dead++;
++ } else if (nexthop_nh->nh_dev == dev &&
++ nexthop_nh->nh_scope != scope) {
++ write_lock_bh(&fib_nhflags_lock);
+ switch (event) {
+ case NETDEV_DOWN:
+ case NETDEV_UNREGISTER:
+@@ -1550,7 +1633,11 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force)
+ }
+ call_fib_nh_notifiers(nexthop_nh,
+ FIB_EVENT_NH_DEL);
+- dead++;
++ write_unlock_bh(&fib_nhflags_lock);
++ if (fi->fib_protocol != RTPROT_STATIC ||
++ force ||
++ __in_dev_get_rtnl(dev) == NULL)
++ dead++;
+ }
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (event == NETDEV_UNREGISTER &&
+@@ -1580,13 +1667,13 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force)
+ }
+
+ /* Must be invoked inside of an RCU protected region. */
+-static void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
++void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
+ {
+ struct fib_info *fi = NULL, *last_resort = NULL;
+ struct hlist_head *fa_head = res->fa_head;
+ struct fib_table *tb = res->table;
+ u8 slen = 32 - res->prefixlen;
+- int order = -1, last_idx = -1;
++ int order = -1, last_idx = -1, last_nhsel = 0;
+ struct fib_alias *fa, *fa1 = NULL;
+ u32 last_prio = res->fi->fib_priority;
+ u8 last_tos = 0;
+@@ -1614,9 +1701,6 @@ static void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
+ if (next_fi->fib_scope != res->scope ||
+ fa->fa_type != RTN_UNICAST)
+ continue;
+- if (!next_fi->fib_nh[0].nh_gw ||
+- next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
+- continue;
+
+ fib_alias_accessed(fa);
+
+@@ -1625,7 +1709,8 @@ static void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
+ break;
+ fa1 = fa;
+ } else if (!fib_detect_death(fi, order, &last_resort,
+- &last_idx, fa1->fa_default)) {
++ &last_idx, fa1->fa_default,
++ &last_nhsel, flp)) {
+ fib_result_assign(res, fi);
+ fa1->fa_default = order;
+ goto out;
+@@ -1635,28 +1720,39 @@ static void fib_select_default(const struct flowi4 *flp, struct fib_result *res)
+ }
+
+ if (order <= 0 || !fi) {
++ if (fi && fi->fib_nhs > 1 &&
++ fib_detect_death(fi, order, &last_resort, &last_idx,
++ fa1->fa_default, &last_nhsel, flp) &&
++ last_resort == fi) {
++ read_lock_bh(&fib_nhflags_lock);
++ fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
++ }
+ if (fa1)
+ fa1->fa_default = -1;
+ goto out;
+ }
+
+ if (!fib_detect_death(fi, order, &last_resort, &last_idx,
+- fa1->fa_default)) {
++ fa1->fa_default, &last_nhsel, flp)) {
+ fib_result_assign(res, fi);
+ fa1->fa_default = order;
+ goto out;
+ }
+
+- if (last_idx >= 0)
++ if (last_idx >= 0) {
+ fib_result_assign(res, last_resort);
++ read_lock_bh(&fib_nhflags_lock);
++ last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
++ }
+ fa1->fa_default = last_idx;
+ out:
+ return;
+ }
+
+ /*
+- * Dead device goes up. We wake up dead nexthops.
+- * It takes sense only on multipath routes.
++ * Dead device goes up or new address is added. We wake up dead nexthops.
+ */
+ int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
+ {
+@@ -1664,8 +1760,10 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
+ unsigned int hash;
+ struct hlist_head *head;
+ struct fib_nh *nh;
+- int ret;
++ struct fib_result res;
++ int ret, rep;
+
++repeat:
+ if (!(dev->flags & IFF_UP))
+ return 0;
+
+@@ -1680,6 +1778,7 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
+ hash = fib_devindex_hashfn(dev->ifindex);
+ head = &fib_info_devhash[hash];
+ ret = 0;
++ rep = 0;
+
+ hlist_for_each_entry(nh, head, nh_hash) {
+ struct fib_info *fi = nh->nh_parent;
+@@ -1692,16 +1791,37 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
+ prev_fi = fi;
+ alive = 0;
+ change_nexthops(fi) {
+- if (!(nexthop_nh->nh_flags & nh_flags)) {
+- alive++;
++ if (!(nexthop_nh->nh_flags & nh_flags))
+ continue;
+- }
+ if (!nexthop_nh->nh_dev ||
+ !(nexthop_nh->nh_dev->flags & IFF_UP))
+ continue;
+ if (nexthop_nh->nh_dev != dev ||
+ !__in_dev_get_rtnl(dev))
+ continue;
++ if ((nh_flags & RTNH_F_DEAD) && nexthop_nh->nh_gw &&
++ fi->fib_protocol == RTPROT_STATIC) {
++ struct flowi4 fl4 = {
++ .daddr = nexthop_nh->nh_gw,
++ .flowi4_scope = nexthop_nh->nh_scope,
++ .flowi4_oif = nexthop_nh->nh_oif,
++ };
++
++ rcu_read_lock();
++ if (fib_lookup(dev_net(dev), &fl4, &res,
++ FIB_LOOKUP_IGNORE_LINKSTATE) != 0) {
++ rcu_read_unlock();
++ continue;
++ }
++ if (res.type != RTN_UNICAST &&
++ res.type != RTN_LOCAL) {
++ rcu_read_unlock();
++ continue;
++ }
++ nexthop_nh->nh_scope = res.scope;
++ rcu_read_unlock();
++ rep = 1;
++ }
+ alive++;
+ nexthop_nh->nh_flags &= ~nh_flags;
+ call_fib_nh_notifiers(nexthop_nh, FIB_EVENT_NH_ADD);
+@@ -1714,6 +1834,8 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
+
+ fib_rebalance(fi);
+ }
++ if (rep)
++ goto repeat;
+
+ return ret;
+ }
+@@ -1767,23 +1889,16 @@ void fib_select_multipath(struct fib_result *res, int hash)
+ void fib_select_path(struct net *net, struct fib_result *res,
+ struct flowi4 *fl4, const struct sk_buff *skb)
+ {
+- if (fl4->flowi4_oif && !(fl4->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF))
+- goto check_saddr;
+-
++ if (res->type == RTN_UNICAST)
++ fib_select_default(fl4, res);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (res->fi->fib_nhs > 1) {
+ int h = fib_multipath_hash(net, fl4, skb, NULL);
+
+ fib_select_multipath(res, h);
+ }
+- else
+ #endif
+- if (!res->prefixlen &&
+- res->table->tb_num_default > 1 &&
+- res->type == RTN_UNICAST)
+- fib_select_default(fl4, res);
+
+-check_saddr:
+ if (!fl4->saddr)
+ fl4->saddr = FIB_RES_PREFSRC(net, *res);
+ }
+diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
+index a573e37e0615..d7572cbcfd7c 100644
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -1482,6 +1482,9 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
+ if (flp->flowi4_oif &&
+ flp->flowi4_oif != nh->nh_oif)
+ continue;
++ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
++ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
++ continue;
+ }
+
+ if (!(fib_flags & FIB_LOOKUP_NOREF))
+diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
+index 007da0882412..10e9d56ea776 100644
+--- a/net/ipv4/netfilter/iptable_nat.c
++++ b/net/ipv4/netfilter/iptable_nat.c
+@@ -43,6 +43,13 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP_PRI_NAT_DST,
+ },
++ /* Before routing, route before mangling */
++ {
++ .hook = ip_nat_route_input,
++ .pf = NFPROTO_IPV4,
++ .hooknum = NF_INET_PRE_ROUTING,
++ .priority = NF_IP_PRI_LAST-1,
++ },
+ {
+ .hook = iptable_nat_do_chain,
+ .pf = NFPROTO_IPV4,
+diff --git a/net/ipv4/route.c b/net/ipv4/route.c
+index 6fdf1c195d8e..b338293debd9 100644
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -1648,7 +1648,7 @@ int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ return -EINVAL;
+ } else {
+ err = fib_validate_source(skb, saddr, 0, tos, 0, dev,
+- in_dev, itag);
++ in_dev, itag, 1);
+ if (err < 0)
+ return err;
+ }
+@@ -1723,7 +1723,7 @@ static void ip_handle_martian_source(struct net_device *dev,
+ static int __mkroute_input(struct sk_buff *skb,
+ const struct fib_result *res,
+ struct in_device *in_dev,
+- __be32 daddr, __be32 saddr, u32 tos)
++ __be32 daddr, __be32 saddr, u32 tos, __be32 lsrc)
+ {
+ struct fib_nh_exception *fnhe;
+ struct rtable *rth;
+@@ -1740,7 +1740,7 @@ static int __mkroute_input(struct sk_buff *skb,
+ }
+
+ err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res),
+- in_dev->dev, in_dev, &itag);
++ in_dev->dev, in_dev, &itag, 0);
+ if (err < 0) {
+ ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
+ saddr);
+@@ -1750,7 +1750,7 @@ static int __mkroute_input(struct sk_buff *skb,
+
+ do_cache = res->fi && !itag;
+ if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&
+- skb->protocol == htons(ETH_P_IP) &&
++ skb->protocol == htons(ETH_P_IP) && !lsrc &&
+ (IN_DEV_SHARED_MEDIA(out_dev) ||
+ inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
+ IPCB(skb)->flags |= IPSKB_DOREDIRECT;
+@@ -1912,10 +1912,12 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4,
+
+ static int ip_mkroute_input(struct sk_buff *skb,
+ struct fib_result *res,
++ const struct flowi4 *fl4,
+ struct in_device *in_dev,
+ __be32 daddr, __be32 saddr, u32 tos,
+- struct flow_keys *hkeys)
++ struct flow_keys *hkeys, __be32 lsrc)
+ {
++ fib_select_default(fl4, res);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (res->fi && res->fi->fib_nhs > 1) {
+ int h = fib_multipath_hash(res->fi->fib_net, NULL, skb, hkeys);
+@@ -1925,7 +1927,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
+ #endif
+
+ /* create a routing cache entry */
+- return __mkroute_input(skb, res, in_dev, daddr, saddr, tos);
++ return __mkroute_input(skb, res, in_dev, daddr, saddr, tos, lsrc);
+ }
+
+ /*
+@@ -1940,7 +1942,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
+ */
+
+ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+- u8 tos, struct net_device *dev,
++ u8 tos, struct net_device *dev, __be32 lsrc,
+ struct fib_result *res)
+ {
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
+@@ -1998,18 +2000,25 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ goto martian_source;
+ }
+
++ if (lsrc) {
++ if (ipv4_is_multicast(lsrc) || ipv4_is_lbcast(lsrc) ||
++ ipv4_is_zeronet(lsrc) || ipv4_is_loopback(lsrc))
++ goto martian_source;
++ }
++
+ /*
+ * Now we are ready to route packet.
+ */
+ fl4.flowi4_oif = 0;
+- fl4.flowi4_iif = dev->ifindex;
++ fl4.flowi4_iif = lsrc ? LOOPBACK_IFINDEX : dev->ifindex;
+ fl4.flowi4_mark = skb->mark;
+ fl4.flowi4_tos = tos;
+ fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
+ fl4.flowi4_flags = 0;
+ fl4.daddr = daddr;
+- fl4.saddr = saddr;
++ fl4.saddr = lsrc? : saddr;
+ fl4.flowi4_uid = sock_net_uid(net, NULL);
++ fl4.fl4_gw = 0;
+
+ if (fib4_rules_early_flow_dissect(net, skb, &fl4, &_flkeys)) {
+ flkeys = &_flkeys;
+@@ -2020,6 +2029,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ }
+
+ err = fib_lookup(net, &fl4, res, 0);
++ fl4.flowi4_iif = dev->ifindex;
++ fl4.saddr = saddr;
+ if (err != 0) {
+ if (!IN_DEV_FORWARD(in_dev))
+ err = -EHOSTUNREACH;
+@@ -2034,7 +2045,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+
+ if (res->type == RTN_LOCAL) {
+ err = fib_validate_source(skb, saddr, daddr, tos,
+- 0, dev, in_dev, &itag);
++ 0, dev, in_dev, &itag, 1);
+ if (err < 0)
+ goto martian_source;
+ goto local_input;
+@@ -2048,16 +2059,19 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ goto martian_destination;
+
+ make_route:
+- err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
++ err = ip_mkroute_input(skb, res, &fl4, in_dev, daddr, saddr, tos,
++ flkeys, lsrc);
+ out: return err;
+
+ brd_input:
+ if (skb->protocol != htons(ETH_P_IP))
+ goto e_inval;
++ if (lsrc)
++ goto e_inval;
+
+ if (!ipv4_is_zeronet(saddr)) {
+ err = fib_validate_source(skb, saddr, 0, tos, 0, dev,
+- in_dev, &itag);
++ in_dev, &itag, 1);
+ if (err < 0)
+ goto martian_source;
+ }
+@@ -2161,9 +2175,26 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ }
+ EXPORT_SYMBOL(ip_route_input_noref);
+
++int ip_route_input_lookup(struct sk_buff *skb, __be32 daddr, __be32 saddr,
++ u8 tos, struct net_device *dev, __be32 lsrc)
++{
++ struct fib_result res;
++ int err;
++
++ tos &= IPTOS_RT_MASK;
++ rcu_read_lock();
++ err = ip_route_input_common_rcu(skb, daddr, saddr, tos, dev, lsrc,
++ &res);
++ rcu_read_unlock();
++
++ return err;
++}
++EXPORT_SYMBOL(ip_route_input_lookup);
++
+ /* called with rcu_read_lock held */
+-int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+- u8 tos, struct net_device *dev, struct fib_result *res)
++int ip_route_input_common_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
++ u8 tos, struct net_device *dev, __be32 lsrc,
++ struct fib_result *res)
+ {
+ /* Multicast recognition logic is moved from route cache to here.
+ The problem was that too many Ethernet cards have broken/missing
+@@ -2209,7 +2240,13 @@ int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+ return err;
+ }
+
+- return ip_route_input_slow(skb, daddr, saddr, tos, dev, res);
++ return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc, res);
++}
++
++int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr,
++ u8 tos, struct net_device *dev, struct fib_result *res)
++{
++ return ip_route_input_common_rcu(skb, daddr, saddr, tos, dev, 0, res);
+ }
+
+ /* called with rcu_read_lock() */
+@@ -2461,6 +2498,7 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
+ fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
+ dev_out = net->loopback_dev;
+ fl4->flowi4_oif = LOOPBACK_IFINDEX;
++ fl4->fl4_gw = 0;
+ res->type = RTN_LOCAL;
+ flags |= RTCF_LOCAL;
+ goto make_route;
+@@ -2519,6 +2557,7 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4,
+ orig_oif = FIB_RES_OIF(*res);
+
+ fl4->flowi4_oif = dev_out->ifindex;
++ fl4->fl4_gw = 0;
+ flags |= RTCF_LOCAL;
+ goto make_route;
+ }
+diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
+index 000952719adf..ff44c43411d7 100644
+--- a/net/netfilter/nf_nat_core.c
++++ b/net/netfilter/nf_nat_core.c
+@@ -1152,6 +1152,49 @@ static struct nf_nat_hook nat_hook = {
+ .manip_pkt = nf_nat_manip_pkt,
+ };
+
++unsigned int ip_nat_route_input(void *priv,
++ struct sk_buff *skb,
++ const struct nf_hook_state *state)
++{
++ struct iphdr *iph;
++ struct nf_conn *conn;
++ enum ip_conntrack_info ctinfo;
++ enum ip_conntrack_dir dir;
++ unsigned long statusbit;
++ __be32 saddr;
++
++ if (!(conn = nf_ct_get(skb, &ctinfo)))
++ return NF_ACCEPT;
++
++ if (!(conn->status & IPS_NAT_DONE_MASK))
++ return NF_ACCEPT;
++ dir = CTINFO2DIR(ctinfo);
++ statusbit = IPS_SRC_NAT;
++ if (dir == IP_CT_DIR_REPLY)
++ statusbit ^= IPS_NAT_MASK;
++ if (!(conn->status & statusbit))
++ return NF_ACCEPT;
++
++ if (skb_dst(skb))
++ return NF_ACCEPT;
++
++ if (skb->len < sizeof(struct iphdr))
++ return NF_ACCEPT;
++
++ /* use daddr in other direction as masquerade address (lsrc) */
++ iph = ip_hdr(skb);
++ saddr = conn->tuplehash[!dir].tuple.dst.u3.ip;
++ if (saddr == iph->saddr)
++ return NF_ACCEPT;
++
++ if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
++ skb->dev, saddr))
++ return NF_DROP;
++
++ return NF_ACCEPT;
++}
++EXPORT_SYMBOL_GPL(ip_nat_route_input);
++
+ static int __init nf_nat_init(void)
+ {
+ int ret, i;
+diff --git a/net/netfilter/nf_nat_masquerade.c b/net/netfilter/nf_nat_masquerade.c
+index d85c4d902e7b..f45df6cf24d7 100644
+--- a/net/netfilter/nf_nat_masquerade.c
++++ b/net/netfilter/nf_nat_masquerade.c
+@@ -23,8 +23,8 @@ nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
+ struct nf_conn_nat *nat;
+ enum ip_conntrack_info ctinfo;
+ struct nf_nat_range2 newrange;
+- const struct rtable *rt;
+- __be32 newsrc, nh;
++ struct rtable *rt;
++ __be32 newsrc;
+
+ WARN_ON(hooknum != NF_INET_POST_ROUTING);
+
+@@ -39,12 +39,23 @@ nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
+ return NF_ACCEPT;
+
+- rt = skb_rtable(skb);
+- nh = rt_nexthop(rt, ip_hdr(skb)->daddr);
+- newsrc = inet_select_addr(out, nh, RT_SCOPE_UNIVERSE);
+- if (!newsrc) {
+- pr_info("%s ate my IP address\n", out->name);
+- return NF_DROP;
++ {
++ struct flowi4 fl4 = { .flowi4_tos = RT_TOS(ip_hdr(skb)->tos),
++ .flowi4_mark = skb->mark,
++ .flowi4_oif = out->ifindex,
++ .daddr = ip_hdr(skb)->daddr,
++ .fl4_gw = skb_rtable(skb)->rt_gateway };
++ rt = ip_route_output_key(dev_net(out), &fl4);
++ if (IS_ERR(rt)) {
++ /* Funky routing can do this. */
++ if (net_ratelimit())
++ pr_info("%s:"
++ " No route: Rusty's brain broke!\n",
++ out->name);
++ return NF_DROP;
++ }
++ newsrc = fl4.saddr;
++ ip_rt_put(rt);
+ }
+
+ nat = nf_ct_nat_ext_add(ct);
+diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
+index 9cec81209617..820ede89c74a 100644
+--- a/security/selinux/nlmsgtab.c
++++ b/security/selinux/nlmsgtab.c
+@@ -83,6 +83,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
+ { RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ },
++ { RTM_NEWARPRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
++ { RTM_DELARPRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
++ { RTM_GETARPRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ };
+
+ static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
+@@ -166,7 +169,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
+ * structures at the top of this file with the new mappings
+ * before updating the BUILD_BUG_ON() macro!
+ */
+- BUILD_BUG_ON(RTM_MAX != (RTM_NEWCHAIN + 3));
++ BUILD_BUG_ON(RTM_MAX != (RTM_NEWARPRULE + 3));
+ err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
+ sizeof(nlmsg_route_perms));
+ break;
diff --git a/sys-kernel/boest-v5.1.1/0002-pool-2.6.25-tcp-timewait-20s.diff.patch b/sys-kernel/boest-v5.1.1/0002-pool-2.6.25-tcp-timewait-20s.diff.patch
new file mode 100644
index 00000000..ae0308a9
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0002-pool-2.6.25-tcp-timewait-20s.diff.patch
@@ -0,0 +1,27 @@
+From 38a0f1b389d85b1fd523d157473dd1886eef03c9 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sun, 15 Feb 2009 14:51:33 +0100
+Subject: [PATCH 02/12] pool/2.6.25-tcp-timewait-20s.diff
+
+From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2
+
+Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh>
+---
+ include/net/tcp.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index 68ee02523b87..af51523854d2 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -118,8 +118,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
+ * initial RTO.
+ */
+
+-#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT
+- * state, about 60 seconds */
++#define TCP_TIMEWAIT_LEN (20*HZ) /* how long to wait to destroy TIME-WAIT
++ * state, about 20 seconds */
+ #define TCP_FIN_TIMEOUT TCP_TIMEWAIT_LEN
+ /* BSD style FIN_WAIT2 deadlock breaker.
+ * It used to be 3min, new value is 60sec,
diff --git a/sys-kernel/boest-v5.1.1/0003-pool-2.6.25-disable-tcp-debug.diff.patch b/sys-kernel/boest-v5.1.1/0003-pool-2.6.25-disable-tcp-debug.diff.patch
new file mode 100644
index 00000000..d98842e7
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0003-pool-2.6.25-disable-tcp-debug.diff.patch
@@ -0,0 +1,25 @@
+From 71db81ed5afde01f301b4202bcd3479df17fffb0 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sun, 15 Feb 2009 14:51:33 +0100
+Subject: [PATCH 03/12] pool/2.6.25-disable-tcp-debug.diff
+
+From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2
+
+Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh>
+---
+ include/net/tcp.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/net/tcp.h b/include/net/tcp.h
+index af51523854d2..61efa5a2868d 100644
+--- a/include/net/tcp.h
++++ b/include/net/tcp.h
+@@ -18,7 +18,7 @@
+ #ifndef _TCP_H
+ #define _TCP_H
+
+-#define FASTRETRANS_DEBUG 1
++#define FASTRETRANS_DEBUG 0
+
+ #include <linux/list.h>
+ #include <linux/tcp.h>
diff --git a/sys-kernel/boest-v5.1.1/0004-TCP-add-a-sysctl-to-disable-simultaneous-connection-.patch b/sys-kernel/boest-v5.1.1/0004-TCP-add-a-sysctl-to-disable-simultaneous-connection-.patch
new file mode 100644
index 00000000..9670cdd5
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0004-TCP-add-a-sysctl-to-disable-simultaneous-connection-.patch
@@ -0,0 +1,142 @@
+From 2279cbf1e033df087cee347e4825dbbda234e493 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Wed, 8 Oct 2008 10:00:42 +0200
+Subject: [PATCH 04/12] TCP: add a sysctl to disable simultaneous connection
+ opening.
+
+Strict implementation of RFC793 (TCP) requires support for a feature
+called "simultaneous connect", which allows two clients to connect to
+each other without anyone entering a listening state. While almost
+never used, and supported by few OSes, Linux supports this feature.
+
+However, it introduces a weakness in the protocol which makes it very
+easy for an attacker to prevent a client from connecting to a known
+server. The attacker only has to guess the source port to shut down
+the client connection during its establishment. The impact is limited,
+but it may be used to prevent an antivirus or IPS from fetching updates
+and not detecting an attack, or to prevent an SSL gateway from fetching
+a CRL for example.
+
+This patch provides a new sysctl "tcp_simult_connect" to enable or disable
+support for this useless feature. It comes disabled by default.
+
+Hundreds of systems running with that feature disabled for more than 4 years
+have never encountered an application which requires it. It is almost never
+supported by firewalls BTW.
+
+From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2
+
+Reviewed-by: Bertrand Jacquin <bertrand@jacquin.bzh>
+
+Signed-off-by: Willy Tarreau <w@1wt.eu>
+Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh>
+---
+ Documentation/networking/ip-sysctl.txt | 22 ++++++++++++++++++++++
+ include/net/netns/ipv4.h | 1 +
+ include/uapi/linux/sysctl.h | 1 +
+ net/ipv4/sysctl_net_ipv4.c | 7 +++++++
+ net/ipv4/tcp_input.c | 6 +++++-
+ 5 files changed, 36 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
+index 5a5d64e4daf5..c65fd0523daa 100644
+--- a/Documentation/networking/ip-sysctl.txt
++++ b/Documentation/networking/ip-sysctl.txt
+@@ -199,6 +199,28 @@ inet_peer_maxttl - INTEGER
+
+ TCP variables:
+
++tcp_simult_connect - BOOLEAN
++ Enables TCP simultaneous connect feature conforming to RFC793.
++ Strict implementation of RFC793 (TCP) requires support for a feature
++ called "simultaneous connect", which allows two clients to connect to
++ each other without anyone entering a listening state. While almost
++ never used, and supported by few OSes, Linux supports this feature.
++
++ However, it introduces a weakness in the protocol which makes it very
++ easy for an attacker to prevent a client from connecting to a known
++ server. The attacker only has to guess the source port to shut down
++ the client connection during its establishment. The impact is limited,
++ but it may be used to prevent an antivirus or IPS from fetching updates
++ and not detecting an attack, or to prevent an SSL gateway from fetching
++ a CRL for example.
++
++ If you want absolute compatibility with any possible application,
++ you should set it to 1. If you prefer to enhance security on your
++ systems you'd better let it to 0. After four years of usage on
++ hundreds of systems, no application was ever found to require this
++ feature, which is not even supported by most firewalls.
++ Default: 0
++
+ somaxconn - INTEGER
+ Limit of socket listen() backlog, known in userspace as SOMAXCONN.
+ Defaults to 128. See also tcp_max_syn_backlog for additional tuning
+diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
+index 104a6669e344..f406fdc12340 100644
+--- a/include/net/netns/ipv4.h
++++ b/include/net/netns/ipv4.h
+@@ -140,6 +140,7 @@ struct netns_ipv4 {
+ int sysctl_tcp_recovery;
+ int sysctl_tcp_thin_linear_timeouts;
+ int sysctl_tcp_slow_start_after_idle;
++ int sysctl_tcp_simult_connect;
+ int sysctl_tcp_retrans_collapse;
+ int sysctl_tcp_stdurg;
+ int sysctl_tcp_rfc1337;
+diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
+index 87aa2a6d9125..c94a1099bc5b 100644
+--- a/include/uapi/linux/sysctl.h
++++ b/include/uapi/linux/sysctl.h
+@@ -426,6 +426,7 @@ enum
+ NET_TCP_ALLOWED_CONG_CONTROL=123,
+ NET_TCP_MAX_SSTHRESH=124,
+ NET_TCP_FRTO_RESPONSE=125,
++ NET_TCP_SIMULT_CONNECT=126,
+ };
+
+ enum {
+diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
+index eeb4041fa5f9..5d6345007a7d 100644
+--- a/net/ipv4/sysctl_net_ipv4.c
++++ b/net/ipv4/sysctl_net_ipv4.c
+@@ -515,6 +515,13 @@ static struct ctl_table ipv4_table[] = {
+ .mode = 0444,
+ .proc_handler = proc_tcp_available_congestion_control,
+ },
++ {
++ .procname = "tcp_simult_connect",
++ .data = &init_net.ipv4.sysctl_tcp_simult_connect,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = &proc_dointvec,
++ },
+ {
+ .procname = "tcp_allowed_congestion_control",
+ .maxlen = TCP_CA_BUF_MAX,
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 731d3045b50a..a4f5ceca4879 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -5752,6 +5752,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
+ const struct tcphdr *th)
+ {
+ struct inet_connection_sock *icsk = inet_csk(sk);
++ struct net *net = sock_net(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct tcp_fastopen_cookie foc = { .len = -1 };
+ int saved_clamp = tp->rx_opt.mss_clamp;
+@@ -5907,10 +5908,13 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
+ tcp_paws_reject(&tp->rx_opt, 0))
+ goto discard_and_undo;
+
+- if (th->syn) {
++ if (th->syn && net->ipv4.sysctl_tcp_simult_connect) {
+ /* We see SYN without ACK. It is attempt of
+ * simultaneous connect with crossed SYNs.
+ * Particularly, it can be connect to self.
++ * This feature is disabled by default as it introduces
++ * weakness in the protocol. It can be enabled by a
++ * sysctl.
+ */
+ tcp_set_state(sk, TCP_SYN_RECV);
+
diff --git a/sys-kernel/boest-v5.1.1/0005-pool-2.6.25-disable-kbdrate-at-boot.diff.patch b/sys-kernel/boest-v5.1.1/0005-pool-2.6.25-disable-kbdrate-at-boot.diff.patch
new file mode 100644
index 00000000..81264de7
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0005-pool-2.6.25-disable-kbdrate-at-boot.diff.patch
@@ -0,0 +1,34 @@
+From b1f687ad3c4b501e9d4a0e1a900a57a9ec650d32 Mon Sep 17 00:00:00 2001
+From: Willy Tarreau <w@1wt.eu>
+Date: Sun, 15 Feb 2009 14:51:33 +0100
+Subject: [PATCH 05/12] pool/2.6.25-disable-kbdrate-at-boot.diff
+
+From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2
+
+Reviewed-by: Bertrand Jacquin <bertrand@jacquin.bzh>
+Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh>
+---
+ arch/x86/boot/main.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
+index 73532543d689..e0d26ecfb713 100644
+--- a/arch/x86/boot/main.c
++++ b/arch/x86/boot/main.c
+@@ -64,6 +64,8 @@ static void copy_boot_params(void)
+ */
+ static void keyboard_init(void)
+ {
++/*This may take several seconds if the system has no kbd controller */
++#ifdef CONFIG_INPUT_KEYBOARD
+ struct biosregs ireg, oreg;
+ initregs(&ireg);
+
+@@ -73,6 +75,7 @@ static void keyboard_init(void)
+
+ ireg.ax = 0x0305; /* Set keyboard repeat rate */
+ intcall(0x16, &ireg, NULL);
++#endif
+ }
+
+ /*
diff --git a/sys-kernel/boest-v5.1.1/0006-Disable-CONFIG_PROCESSOR_SELECT-printk-s.patch b/sys-kernel/boest-v5.1.1/0006-Disable-CONFIG_PROCESSOR_SELECT-printk-s.patch
new file mode 100644
index 00000000..f5838ebf
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0006-Disable-CONFIG_PROCESSOR_SELECT-printk-s.patch
@@ -0,0 +1,45 @@
+From 6ddba75f963a2f617248487cc8f6635def90c4dc Mon Sep 17 00:00:00 2001
+From: Bertrand Jacquin <bertrand@jacquin.bzh>
+Date: Wed, 9 Jan 2013 00:28:28 +0100
+Subject: [PATCH 06/12] Disable CONFIG_PROCESSOR_SELECT printk()'s
+
+Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh>
+---
+ arch/x86/kernel/cpu/common.c | 17 -----------------
+ 1 file changed, 17 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
+index cb28e98a0659..e6c914785fad 100644
+--- a/arch/x86/kernel/cpu/common.c
++++ b/arch/x86/kernel/cpu/common.c
+@@ -1137,10 +1137,6 @@ void __init early_cpu_init(void)
+ const struct cpu_dev *const *cdev;
+ int count = 0;
+
+-#ifdef CONFIG_PROCESSOR_SELECT
+- pr_info("KERNEL supported cpus:\n");
+-#endif
+-
+ for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
+ const struct cpu_dev *cpudev = *cdev;
+
+@@ -1148,19 +1144,6 @@ void __init early_cpu_init(void)
+ break;
+ cpu_devs[count] = cpudev;
+ count++;
+-
+-#ifdef CONFIG_PROCESSOR_SELECT
+- {
+- unsigned int j;
+-
+- for (j = 0; j < 2; j++) {
+- if (!cpudev->c_ident[j])
+- continue;
+- pr_info(" %s %s\n", cpudev->c_vendor,
+- cpudev->c_ident[j]);
+- }
+- }
+-#endif
+ }
+ early_identify_cpu(&boot_cpu_data);
+ }
diff --git a/sys-kernel/boest-v5.1.1/0007-This-patch-adds-support-for-a-restricted-user-contro.patch b/sys-kernel/boest-v5.1.1/0007-This-patch-adds-support-for-a-restricted-user-contro.patch
new file mode 100644
index 00000000..82b59610
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0007-This-patch-adds-support-for-a-restricted-user-contro.patch
@@ -0,0 +1,75 @@
+From 7ccd619a2e89a05f4f5992a286e58b3eeac1c0b4 Mon Sep 17 00:00:00 2001
+From: "Anthony G. Basile" <blueness@gentoo.org>
+Date: Sun, 21 Apr 2019 16:05:59 -0400
+Subject: [PATCH 07/12] This patch adds support for a restricted
+ user-controlled namespace on tmpfs filesystem used to house PaX flags. The
+ namespace must be of the form user.pax.* and its value cannot exceed a size
+ of 8 bytes.
+
+This is needed even on all Gentoo systems so that XATTR_PAX flags
+are preserved for users who might build packages using portage on
+a tmpfs system with a non-hardened kernel and then switch to a
+hardened kernel with XATTR_PAX enabled.
+
+The namespace is added to any user with Extended Attribute support
+enabled for tmpfs. Users who do not enable xattrs will not have
+the XATTR_PAX flags preserved.
+---
+ include/uapi/linux/xattr.h | 4 ++++
+ mm/shmem.c | 15 +++++++++++++++
+ 2 files changed, 19 insertions(+)
+
+diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
+index c1395b5bd432..bac6d48eca8e 100644
+--- a/include/uapi/linux/xattr.h
++++ b/include/uapi/linux/xattr.h
+@@ -77,5 +77,9 @@
+ #define XATTR_POSIX_ACL_DEFAULT "posix_acl_default"
+ #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
+
++/* User namespace */
++#define XATTR_PAX_PREFIX XATTR_USER_PREFIX "pax."
++#define XATTR_PAX_FLAGS_SUFFIX "flags"
++#define XATTR_NAME_PAX_FLAGS XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX
+
+ #endif /* _UAPI_LINUX_XATTR_H */
+diff --git a/mm/shmem.c b/mm/shmem.c
+index 2275a0ff7c30..8cb1d2571c33 100644
+--- a/mm/shmem.c
++++ b/mm/shmem.c
+@@ -3220,6 +3220,14 @@ static int shmem_xattr_handler_set(const struct xattr_handler *handler,
+ struct shmem_inode_info *info = SHMEM_I(inode);
+
+ name = xattr_full_name(handler, name);
++
++ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
++ if (strcmp(name, XATTR_NAME_PAX_FLAGS))
++ return -EOPNOTSUPP;
++ if (size > 8)
++ return -EINVAL;
++ }
++
+ return simple_xattr_set(&info->xattrs, name, value, size, flags);
+ }
+
+@@ -3235,6 +3243,12 @@ static const struct xattr_handler shmem_trusted_xattr_handler = {
+ .set = shmem_xattr_handler_set,
+ };
+
++static const struct xattr_handler shmem_user_xattr_handler = {
++ .prefix = XATTR_USER_PREFIX,
++ .get = shmem_xattr_handler_get,
++ .set = shmem_xattr_handler_set,
++};
++
+ static const struct xattr_handler *shmem_xattr_handlers[] = {
+ #ifdef CONFIG_TMPFS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+@@ -3242,6 +3256,7 @@ static const struct xattr_handler *shmem_xattr_handlers[] = {
+ #endif
+ &shmem_security_xattr_handler,
+ &shmem_trusted_xattr_handler,
++ &shmem_user_xattr_handler,
+ NULL
+ };
+
diff --git a/sys-kernel/boest-v5.1.1/0008-fs-Enable-link-security-restrictions-by-default.patch b/sys-kernel/boest-v5.1.1/0008-fs-Enable-link-security-restrictions-by-default.patch
new file mode 100644
index 00000000..fa59735c
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0008-fs-Enable-link-security-restrictions-by-default.patch
@@ -0,0 +1,26 @@
+From 6c1bc2ecb3d78560b371139c909b1031c590a448 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Fri, 2 Nov 2012 05:32:06 +0000
+Subject: [PATCH 08/12] fs: Enable link security restrictions by default
+
+This reverts commit 561ec64ae67ef25cac8d72bb9c4bfc955edfd415
+('VFS: don't do protected {sym,hard}links by default').
+---
+ fs/namei.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/namei.c b/fs/namei.c
+index dede0147b3f6..cc9ce8705551 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -883,8 +883,8 @@ static inline void put_link(struct nameidata *nd)
+ path_put(&last->link);
+ }
+
+-int sysctl_protected_symlinks __read_mostly = 0;
+-int sysctl_protected_hardlinks __read_mostly = 0;
++int sysctl_protected_symlinks __read_mostly = 1;
++int sysctl_protected_hardlinks __read_mostly = 1;
+ int sysctl_protected_fifos __read_mostly;
+ int sysctl_protected_regular __read_mostly;
+
diff --git a/sys-kernel/boest-v5.1.1/0009-usb-storage-Disable-UAS-on-JMicron-SATA-enclosure.patch b/sys-kernel/boest-v5.1.1/0009-usb-storage-Disable-UAS-on-JMicron-SATA-enclosure.patch
new file mode 100644
index 00000000..84a45c2c
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0009-usb-storage-Disable-UAS-on-JMicron-SATA-enclosure.patch
@@ -0,0 +1,37 @@
+From 6a1d594236d639c536b9ed95deaab56061635b7c Mon Sep 17 00:00:00 2001
+From: Laura Abbott <labbott@fedoraproject.org>
+Date: Tue, 8 Sep 2015 09:53:38 -0700
+Subject: [PATCH 09/12] usb-storage: Disable UAS on JMicron SATA enclosure
+
+Steve Ellis reported incorrect block sizes and alignement
+offsets with a SATA enclosure. Adding a quirk to disable
+UAS fixes the problems.
+
+Reported-by: Steven Ellis <sellis@redhat.com>
+Signed-off-by: Laura Abbott <labbott@fedoraproject.org>
+---
+ drivers/usb/storage/unusual_uas.h | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
+index d0bdebd87ce3..1b23741036ee 100644
+--- a/drivers/usb/storage/unusual_uas.h
++++ b/drivers/usb/storage/unusual_uas.h
+@@ -87,12 +87,15 @@ UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999,
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_IGNORE_UAS),
+
+-/* Reported-by: Takeo Nakayama <javhera@gmx.com> */
++/*
++ * Initially Reported-by: Takeo Nakayama <javhera@gmx.com>
++ * UAS Ignore Reported by Steven Ellis <sellis@redhat.com>
++ */
+ UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999,
+ "JMicron",
+ "JMS566",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+- US_FL_NO_REPORT_OPCODES),
++ US_FL_NO_REPORT_OPCODES | US_FL_IGNORE_UAS),
+
+ /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+ UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
diff --git a/sys-kernel/boest-v5.1.1/0010-5.1-2600_enable-key-swapping-for-apple-mac.patch.patch b/sys-kernel/boest-v5.1.1/0010-5.1-2600_enable-key-swapping-for-apple-mac.patch.patch
new file mode 100644
index 00000000..557e2f48
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0010-5.1-2600_enable-key-swapping-for-apple-mac.patch.patch
@@ -0,0 +1,125 @@
+From 337d3626ee5c3f6d854fa3a21939ad25ac8382aa Mon Sep 17 00:00:00 2001
+From: Mike Pagano <mpagano@gentoo.org>
+Date: Sun, 21 Apr 2019 16:05:59 -0400
+Subject: [PATCH 10/12] 5.1:2600_enable-key-swapping-for-apple-mac.patch
+
+---
+ drivers/hid/hid-apple.c | 76 +++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 74 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
+index 1cb41992aaa1..c34a3be5085a 100644
+--- a/drivers/hid/hid-apple.c
++++ b/drivers/hid/hid-apple.c
+@@ -54,6 +54,22 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\")
+ "(For people who want to keep Windows PC keyboard muscle memory. "
+ "[0] = as-is, Mac layout. 1 = swapped, Windows layout.)");
+
++static unsigned int swap_fn_leftctrl;
++module_param(swap_fn_leftctrl, uint, 0644);
++MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
++ "(For people who want to keep PC keyboard muscle memory. "
++ "[0] = as-is, Mac layout, 1 = swapped, PC layout)");
++
++static unsigned int rightalt_as_rightctrl;
++module_param(rightalt_as_rightctrl, uint, 0644);
++MODULE_PARM_DESC(rightalt_as_rightctrl, "Use the right Alt key as a right Ctrl key. "
++ "[0] = as-is, Mac layout. 1 = Right Alt is right Ctrl");
++
++static unsigned int ejectcd_as_delete;
++module_param(ejectcd_as_delete, uint, 0644);
++MODULE_PARM_DESC(ejectcd_as_delete, "Use Eject-CD key as Delete key. "
++ "([0] = disabled, 1 = enabled)");
++
+ struct apple_sc {
+ unsigned long quirks;
+ unsigned int fn_on;
+@@ -166,6 +182,21 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = {
+ { }
+ };
+
++static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
++ { KEY_FN, KEY_LEFTCTRL },
++ { }
++};
++
++static const struct apple_key_translation rightalt_as_rightctrl_keys[] = {
++ { KEY_RIGHTALT, KEY_RIGHTCTRL },
++ { }
++};
++
++static const struct apple_key_translation ejectcd_as_delete_keys[] = {
++ { KEY_EJECTCD, KEY_DELETE },
++ { }
++};
++
+ static const struct apple_key_translation *apple_find_translation(
+ const struct apple_key_translation *table, u16 from)
+ {
+@@ -185,9 +216,11 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
+ struct apple_sc *asc = hid_get_drvdata(hid);
+ const struct apple_key_translation *trans, *table;
+
+- if (usage->code == KEY_FN) {
++ u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
++
++ if (usage->code == fn_keycode) {
+ asc->fn_on = !!value;
+- input_event(input, usage->type, usage->code, value);
++ input_event(input, usage->type, KEY_FN, value);
+ return 1;
+ }
+
+@@ -266,6 +299,30 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
+ }
+ }
+
++ if (swap_fn_leftctrl) {
++ trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code);
++ if (trans) {
++ input_event(input, usage->type, trans->to, value);
++ return 1;
++ }
++ }
++
++ if (ejectcd_as_delete) {
++ trans = apple_find_translation(ejectcd_as_delete_keys, usage->code);
++ if (trans) {
++ input_event(input, usage->type, trans->to, value);
++ return 1;
++ }
++ }
++
++ if (rightalt_as_rightctrl) {
++ trans = apple_find_translation(rightalt_as_rightctrl_keys, usage->code);
++ if (trans) {
++ input_event(input, usage->type, trans->to, value);
++ return 1;
++ }
++ }
++
+ return 0;
+ }
+
+@@ -329,6 +386,21 @@ static void apple_setup_input(struct input_dev *input)
+
+ for (trans = apple_iso_keyboard; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
++
++ if (swap_fn_leftctrl) {
++ for (trans = swapped_fn_leftctrl_keys; trans->from; trans++)
++ set_bit(trans->to, input->keybit);
++ }
++
++ if (ejectcd_as_delete) {
++ for (trans = ejectcd_as_delete_keys; trans->from; trans++)
++ set_bit(trans->to, input->keybit);
++ }
++
++ if (rightalt_as_rightctrl) {
++ for (trans = rightalt_as_rightctrl_keys; trans->from; trans++)
++ set_bit(trans->to, input->keybit);
++ }
+ }
+
+ static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
diff --git a/sys-kernel/boest-v5.1.1/0011-5.1-4567_distro-Gentoo-Kconfig.patch.patch b/sys-kernel/boest-v5.1.1/0011-5.1-4567_distro-Gentoo-Kconfig.patch.patch
new file mode 100644
index 00000000..3a419508
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0011-5.1-4567_distro-Gentoo-Kconfig.patch.patch
@@ -0,0 +1,173 @@
+From 8757f9c98a8582ab896a24bf238609e63492d446 Mon Sep 17 00:00:00 2001
+From: Mike Pagano <mpagano@gentoo.org>
+Date: Fri, 28 Dec 2018 18:58:06 -0500
+Subject: [PATCH 11/12] 5.1:4567_distro-Gentoo-Kconfig.patch
+
+---
+ Kconfig | 2 +
+ distro/Kconfig | 147 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 149 insertions(+)
+
+diff --git a/Kconfig b/Kconfig
+index 48a80beab685..a5ad73c66099 100644
+--- a/Kconfig
++++ b/Kconfig
+@@ -30,3 +30,5 @@ source "crypto/Kconfig"
+ source "lib/Kconfig"
+
+ source "lib/Kconfig.debug"
++
++source "distro/Kconfig"
+diff --git a/distro/Kconfig b/distro/Kconfig
+new file mode 100644
+index 000000000000..cc385887e08a
+--- /dev/null
++++ b/distro/Kconfig
+@@ -0,0 +1,147 @@
++menu "Gentoo Linux"
++
++config GENTOO_LINUX
++ bool "Gentoo Linux support"
++++
++ default y
++
++ help
++ In order to boot Gentoo Linux a minimal set of config settings needs to
++ be enabled in the kernel; to avoid the users from having to enable them
++ manually as part of a Gentoo Linux installation or a new clean config,
++ we enable these config settings by default for convenience.
++
++ See the settings that become available for more details and fine-tuning.
++
++config GENTOO_LINUX_UDEV
++ bool "Linux dynamic and persistent device naming (userspace devfs) support"
++
++ depends on GENTOO_LINUX
++ default y if GENTOO_LINUX
++
++ select DEVTMPFS
++ select TMPFS
++ select UNIX
++
++ select MMU
++ select SHMEM
++
++ help
++ In order to boot Gentoo Linux a minimal set of config settings needs to
++ be enabled in the kernel; to avoid the users from having to enable them
++ manually as part of a Gentoo Linux installation or a new clean config,
++ we enable these config settings by default for convenience.
++
++ Currently this only selects TMPFS, DEVTMPFS and their dependencies.
++ TMPFS is enabled to maintain a tmpfs file system at /dev/shm, /run and
++ /sys/fs/cgroup; DEVTMPFS to maintain a devtmpfs file system at /dev.
++
++ Some of these are critical files that need to be available early in the
++ boot process; if not available, it causes sysfs and udev to malfunction.
++
++ To ensure Gentoo Linux boots, it is best to leave this setting enabled;
++ if you run a custom setup, you could consider whether to disable this.
++
++config GENTOO_LINUX_PORTAGE
++ bool "Select options required by Portage features"
++
++ depends on GENTOO_LINUX
++ default y if GENTOO_LINUX
++
++ select CGROUPS
++ select NAMESPACES
++ select IPC_NS
++ select NET_NS
++ select PID_NS
++ select SYSVIPC
++
++ help
++ This enables options required by various Portage FEATURES.
++ Currently this selects:
++
++ CGROUPS (required for FEATURES=cgroup)
++ IPC_NS (required for FEATURES=ipc-sandbox)
++ NET_NS (required for FEATURES=network-sandbox)
++ PID_NS (required for FEATURES=pid-sandbox)
++ SYSVIPC (required by IPC_NS)
++
++
++ It is highly recommended that you leave this enabled as these FEATURES
++ are, or will soon be, enabled by default.
++
++menu "Support for init systems, system and service managers"
++ visible if GENTOO_LINUX
++
++config GENTOO_LINUX_INIT_SCRIPT
++ bool "OpenRC, runit and other script based systems and managers"
++
++ default y if GENTOO_LINUX
++
++ depends on GENTOO_LINUX
++
++ select BINFMT_SCRIPT
++
++ help
++ The init system is the first thing that loads after the kernel booted.
++
++ These config settings allow you to select which init systems to support;
++ instead of having to select all the individual settings all over the
++ place, these settings allows you to select all the settings at once.
++
++ This particular setting enables all the known requirements for OpenRC,
++ runit and similar script based systems and managers.
++
++ If you are unsure about this, it is best to leave this setting enabled.
++
++config GENTOO_LINUX_INIT_SYSTEMD
++ bool "systemd"
++
++ default n
++
++ depends on GENTOO_LINUX && GENTOO_LINUX_UDEV
++
++ select AUTOFS4_FS
++ select BLK_DEV_BSG
++ select CGROUPS
++ select CHECKPOINT_RESTORE
++ select CRYPTO_HMAC
++ select CRYPTO_SHA256
++ select CRYPTO_USER_API_HASH
++ select DEVPTS_MULTIPLE_INSTANCES
++ select DMIID if X86_32 || X86_64 || X86
++ select EPOLL
++ select FANOTIFY
++ select FHANDLE
++ select INOTIFY_USER
++ select IPV6
++ select NET
++ select NET_NS
++ select PROC_FS
++ select SECCOMP
++ select SECCOMP_FILTER
++ select SIGNALFD
++ select SYSFS
++ select TIMERFD
++ select TMPFS_POSIX_ACL
++ select TMPFS_XATTR
++
++ select ANON_INODES
++ select BLOCK
++ select EVENTFD
++ select FSNOTIFY
++ select INET
++ select NLATTR
++
++ help
++ The init system is the first thing that loads after the kernel booted.
++
++ These config settings allow you to select which init systems to support;
++ instead of having to select all the individual settings all over the
++ place, these settings allows you to select all the settings at once.
++
++ This particular setting enables all the known requirements for systemd;
++ it also enables suggested optional settings, as the package suggests to.
++
++endmenu
++
++endmenu
diff --git a/sys-kernel/boest-v5.1.1/0012-WARNING.patch b/sys-kernel/boest-v5.1.1/0012-WARNING.patch
new file mode 100644
index 00000000..66c5f0c5
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/0012-WARNING.patch
@@ -0,0 +1,565 @@
+From 07a93a8ba8ebe5f5c5aa0d93ed910c1b03d79c7c Mon Sep 17 00:00:00 2001
+From: Mike Pagano <mpagano@gentoo.org>
+Date: Fri, 10 May 2019 19:39:45 -0400
+Subject: [PATCH 12/12] WARNING This patch works with gcc versions 4.9+ and
+ with kernel version 4.13+ and should NOT be applied when compiling on older
+ versions of gcc due to key name changes of the march flags introduced with
+ the version 4.9 release of gcc.[1]
+
+Use the older version of this patch hosted on the same github for older
+versions of gcc.
+
+FEATURES
+This patch adds additional CPU options to the Linux kernel accessible under:
+ Processor type and features --->
+ Processor family --->
+
+The expanded microarchitectures include:
+* AMD Improved K8-family
+* AMD K10-family
+* AMD Family 10h (Barcelona)
+* AMD Family 14h (Bobcat)
+* AMD Family 16h (Jaguar)
+* AMD Family 15h (Bulldozer)
+* AMD Family 15h (Piledriver)
+* AMD Family 15h (Steamroller)
+* AMD Family 15h (Excavator)
+* AMD Family 17h (Zen)
+* Intel Silvermont low-power processors
+* Intel 1st Gen Core i3/i5/i7 (Nehalem)
+* Intel 1.5 Gen Core i3/i5/i7 (Westmere)
+* Intel 2nd Gen Core i3/i5/i7 (Sandybridge)
+* Intel 3rd Gen Core i3/i5/i7 (Ivybridge)
+* Intel 4th Gen Core i3/i5/i7 (Haswell)
+* Intel 5th Gen Core i3/i5/i7 (Broadwell)
+* Intel 6th Gen Core i3/i5/i7 (Skylake)
+* Intel 6th Gen Core i7/i9 (Skylake X)
+
+It also offers to compile passing the 'native' option which, "selects the CPU
+to generate code for at compilation time by determining the processor type of
+the compiling machine. Using -march=native enables all instruction subsets
+supported by the local machine and will produce code optimized for the local
+machine under the constraints of the selected instruction set."[3]
+
+MINOR NOTES
+This patch also changes 'atom' to 'bonnell' in accordance with the gcc v4.9
+changes. Note that upstream is using the deprecated 'match=atom' flags when I
+believe it should use the newer 'march=bonnell' flag for atom processors.[2]
+
+It is not recommended to compile on Atom-CPUs with the 'native' option.[4] The
+recommendation is to use the 'atom' option instead.
+
+BENEFITS
+Small but real speed increases are measurable using a make endpoint comparing
+a generic kernel to one built with one of the respective microarchs.
+
+See the following experimental evidence supporting this statement:
+https://github.com/graysky2/kernel_gcc_patch
+
+REQUIREMENTS
+linux version >=4.13
+gcc version >=4.9
+
+ACKNOWLEDGMENTS
+This patch builds on the seminal work by Jeroen.[5]
+
+REFERENCES
+1. https://gcc.gnu.org/gcc-4.9/changes.html
+2. https://bugzilla.kernel.org/show_bug.cgi?id=77461
+3. https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
+4. https://github.com/graysky2/kernel_gcc_patch/issues/15
+5. http://www.linuxforge.net/docs/linux/linux-gcc.php
+---
+ arch/x86/Kconfig.cpu | 235 +++++++++++++++++++++++++++++-----
+ arch/x86/Makefile | 35 ++++-
+ arch/x86/Makefile_32.cpu | 24 +++-
+ arch/x86/include/asm/module.h | 40 ++++++
+ 4 files changed, 297 insertions(+), 37 deletions(-)
+
+diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
+index 6adce15268bd..7d0709e548af 100644
+--- a/arch/x86/Kconfig.cpu
++++ b/arch/x86/Kconfig.cpu
+@@ -116,6 +116,7 @@ config MPENTIUMM
+ config MPENTIUM4
+ bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/older Xeon"
+ depends on X86_32
++ select X86_P6_NOP
+ ---help---
+ Select this for Intel Pentium 4 chips. This includes the
+ Pentium 4, Pentium D, P4-based Celeron and Xeon, and
+@@ -148,9 +149,8 @@ config MPENTIUM4
+ -Paxville
+ -Dempsey
+
+-
+ config MK6
+- bool "K6/K6-II/K6-III"
++ bool "AMD K6/K6-II/K6-III"
+ depends on X86_32
+ ---help---
+ Select this for an AMD K6-family processor. Enables use of
+@@ -158,7 +158,7 @@ config MK6
+ flags to GCC.
+
+ config MK7
+- bool "Athlon/Duron/K7"
++ bool "AMD Athlon/Duron/K7"
+ depends on X86_32
+ ---help---
+ Select this for an AMD Athlon K7-family processor. Enables use of
+@@ -166,12 +166,83 @@ config MK7
+ flags to GCC.
+
+ config MK8
+- bool "Opteron/Athlon64/Hammer/K8"
++ bool "AMD Opteron/Athlon64/Hammer/K8"
+ ---help---
+ Select this for an AMD Opteron or Athlon64 Hammer-family processor.
+ Enables use of some extended instructions, and passes appropriate
+ optimization flags to GCC.
+
++config MK8SSE3
++ bool "AMD Opteron/Athlon64/Hammer/K8 with SSE3"
++ ---help---
++ Select this for improved AMD Opteron or Athlon64 Hammer-family processors.
++ Enables use of some extended instructions, and passes appropriate
++ optimization flags to GCC.
++
++config MK10
++ bool "AMD 61xx/7x50/PhenomX3/X4/II/K10"
++ ---help---
++ Select this for an AMD 61xx Eight-Core Magny-Cours, Athlon X2 7x50,
++ Phenom X3/X4/II, Athlon II X2/X3/X4, or Turion II-family processor.
++ Enables use of some extended instructions, and passes appropriate
++ optimization flags to GCC.
++
++config MBARCELONA
++ bool "AMD Barcelona"
++ ---help---
++ Select this for AMD Family 10h Barcelona processors.
++
++ Enables -march=barcelona
++
++config MBOBCAT
++ bool "AMD Bobcat"
++ ---help---
++ Select this for AMD Family 14h Bobcat processors.
++
++ Enables -march=btver1
++
++config MJAGUAR
++ bool "AMD Jaguar"
++ ---help---
++ Select this for AMD Family 16h Jaguar processors.
++
++ Enables -march=btver2
++
++config MBULLDOZER
++ bool "AMD Bulldozer"
++ ---help---
++ Select this for AMD Family 15h Bulldozer processors.
++
++ Enables -march=bdver1
++
++config MPILEDRIVER
++ bool "AMD Piledriver"
++ ---help---
++ Select this for AMD Family 15h Piledriver processors.
++
++ Enables -march=bdver2
++
++config MSTEAMROLLER
++ bool "AMD Steamroller"
++ ---help---
++ Select this for AMD Family 15h Steamroller processors.
++
++ Enables -march=bdver3
++
++config MEXCAVATOR
++ bool "AMD Excavator"
++ ---help---
++ Select this for AMD Family 15h Excavator processors.
++
++ Enables -march=bdver4
++
++config MZEN
++ bool "AMD Zen"
++ ---help---
++ Select this for AMD Family 17h Zen processors.
++
++ Enables -march=znver1
++
+ config MCRUSOE
+ bool "Crusoe"
+ depends on X86_32
+@@ -253,6 +324,7 @@ config MVIAC7
+
+ config MPSC
+ bool "Intel P4 / older Netburst based Xeon"
++ select X86_P6_NOP
+ depends on X86_64
+ ---help---
+ Optimize for Intel Pentium 4, Pentium D and older Nocona/Dempsey
+@@ -262,17 +334,9 @@ config MPSC
+ using the cpu family field
+ in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one.
+
+-config MCORE2
+- bool "Core 2/newer Xeon"
+- ---help---
+-
+- Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and
+- 53xx) CPUs. You can distinguish newer from older Xeons by the CPU
+- family in /proc/cpuinfo. Newer ones have 6 and older ones 15
+- (not a typo)
+-
+ config MATOM
+ bool "Intel Atom"
++ select X86_P6_NOP
+ ---help---
+
+ Select this for the Intel Atom platform. Intel Atom CPUs have an
+@@ -280,6 +344,99 @@ config MATOM
+ accordingly optimized code. Use a recent GCC with specific Atom
+ support in order to fully benefit from selecting this option.
+
++config MCORE2
++ bool "Intel Core 2"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and
++ 53xx) CPUs. You can distinguish newer from older Xeons by the CPU
++ family in /proc/cpuinfo. Newer ones have 6 and older ones 15
++ (not a typo)
++
++ Enables -march=core2
++
++config MNEHALEM
++ bool "Intel Nehalem"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for 1st Gen Core processors in the Nehalem family.
++
++ Enables -march=nehalem
++
++config MWESTMERE
++ bool "Intel Westmere"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for the Intel Westmere formerly Nehalem-C family.
++
++ Enables -march=westmere
++
++config MSILVERMONT
++ bool "Intel Silvermont"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for the Intel Silvermont platform.
++
++ Enables -march=silvermont
++
++config MSANDYBRIDGE
++ bool "Intel Sandy Bridge"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for 2nd Gen Core processors in the Sandy Bridge family.
++
++ Enables -march=sandybridge
++
++config MIVYBRIDGE
++ bool "Intel Ivy Bridge"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for 3rd Gen Core processors in the Ivy Bridge family.
++
++ Enables -march=ivybridge
++
++config MHASWELL
++ bool "Intel Haswell"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for 4th Gen Core processors in the Haswell family.
++
++ Enables -march=haswell
++
++config MBROADWELL
++ bool "Intel Broadwell"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for 5th Gen Core processors in the Broadwell family.
++
++ Enables -march=broadwell
++
++config MSKYLAKE
++ bool "Intel Skylake"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for 6th Gen Core processors in the Skylake family.
++
++ Enables -march=skylake
++
++config MSKYLAKEX
++ bool "Intel Skylake X"
++ select X86_P6_NOP
++ ---help---
++
++ Select this for 6th Gen Core processors in the Skylake X family.
++
++ Enables -march=skylake-avx512
++
+ config GENERIC_CPU
+ bool "Generic-x86-64"
+ depends on X86_64
+@@ -287,6 +444,19 @@ config GENERIC_CPU
+ Generic x86-64 CPU.
+ Run equally well on all x86-64 CPUs.
+
++config MNATIVE
++ bool "Native optimizations autodetected by GCC"
++ ---help---
++
++ GCC 4.2 and above support -march=native, which automatically detects
++ the optimum settings to use based on your processor. -march=native
++ also detects and applies additional settings beyond -march specific
++ to your CPU, (eg. -msse4). Unless you have a specific reason not to
++ (e.g. distcc cross-compiling), you should probably be using
++ -march=native rather than anything listed below.
++
++ Enables -march=native
++
+ endchoice
+
+ config X86_GENERIC
+@@ -311,7 +481,7 @@ config X86_INTERNODE_CACHE_SHIFT
+ config X86_L1_CACHE_SHIFT
+ int
+ default "7" if MPENTIUM4 || MPSC
+- default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
++ default "6" if MK7 || MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MJAGUAR || MPENTIUMM || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
+ default "4" if MELAN || M486 || MGEODEGX1
+ default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
+
+@@ -329,35 +499,36 @@ config X86_ALIGNMENT_16
+
+ config X86_INTEL_USERCOPY
+ def_bool y
+- depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2
++ depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK8SSE3 || MK7 || MEFFICEON || MCORE2 || MK10 || MBARCELONA || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE
+
+ config X86_USE_PPRO_CHECKSUM
+ def_bool y
+- depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM
++ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MK10 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MATOM || MNATIVE
+
+ config X86_USE_3DNOW
+ def_bool y
+ depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
+
+-#
+-# P6_NOPs are a relatively minor optimization that require a family >=
+-# 6 processor, except that it is broken on certain VIA chips.
+-# Furthermore, AMD chips prefer a totally different sequence of NOPs
+-# (which work on all CPUs). In addition, it looks like Virtual PC
+-# does not understand them.
+-#
+-# As a result, disallow these if we're not compiling for X86_64 (these
+-# NOPs do work on all x86-64 capable chips); the list of processors in
+-# the right-hand clause are the cores that benefit from this optimization.
+-#
+ config X86_P6_NOP
+- def_bool y
+- depends on X86_64
+- depends on (MCORE2 || MPENTIUM4 || MPSC)
++ default n
++ bool "Support for P6_NOPs on Intel chips"
++ depends on (MCORE2 || MPENTIUM4 || MPSC || MATOM || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE)
++ ---help---
++ P6_NOPs are a relatively minor optimization that require a family >=
++ 6 processor, except that it is broken on certain VIA chips.
++ Furthermore, AMD chips prefer a totally different sequence of NOPs
++ (which work on all CPUs). In addition, it looks like Virtual PC
++ does not understand them.
++
++ As a result, disallow these if we're not compiling for X86_64 (these
++ NOPs do work on all x86-64 capable chips); the list of processors in
++ the right-hand clause are the cores that benefit from this optimization.
++
++ Say Y if you have Intel CPU newer than Pentium Pro, N otherwise.
+
+ config X86_TSC
+ def_bool y
+- depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64
++ depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE || MATOM) || X86_64
+
+ config X86_CMPXCHG64
+ def_bool y
+@@ -367,7 +538,7 @@ config X86_CMPXCHG64
+ # generates cmov.
+ config X86_CMOV
+ def_bool y
+- depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX)
++ depends on (MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MJAGUAR || MK7 || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MNATIVE || MATOM || MGEODE_LX)
+
+ config X86_MINIMUM_CPU_FAMILY
+ int
+diff --git a/arch/x86/Makefile b/arch/x86/Makefile
+index a587805c6687..4bcabbf10e9b 100644
+--- a/arch/x86/Makefile
++++ b/arch/x86/Makefile
+@@ -118,13 +118,42 @@ else
+ KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup)
+
+ # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
++ cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native)
+ cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
++ cflags-$(CONFIG_MK8SSE3) += $(call cc-option,-march=k8-sse3,-mtune=k8)
++ cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10)
++ cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona)
++ cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1)
++ cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2)
++ cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1)
++ cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2)
++ cflags-$(CONFIG_MSTEAMROLLER) += $(call cc-option,-march=bdver3)
++ cflags-$(CONFIG_MEXCAVATOR) += $(call cc-option,-march=bdver4)
++ cflags-$(CONFIG_MZEN) += $(call cc-option,-march=znver1)
+ cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
+
+ cflags-$(CONFIG_MCORE2) += \
+- $(call cc-option,-march=core2,$(call cc-option,-mtune=generic))
+- cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom) \
+- $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
++ $(call cc-option,-march=core2,$(call cc-option,-mtune=core2))
++ cflags-$(CONFIG_MNEHALEM) += \
++ $(call cc-option,-march=nehalem,$(call cc-option,-mtune=nehalem))
++ cflags-$(CONFIG_MWESTMERE) += \
++ $(call cc-option,-march=westmere,$(call cc-option,-mtune=westmere))
++ cflags-$(CONFIG_MSILVERMONT) += \
++ $(call cc-option,-march=silvermont,$(call cc-option,-mtune=silvermont))
++ cflags-$(CONFIG_MSANDYBRIDGE) += \
++ $(call cc-option,-march=sandybridge,$(call cc-option,-mtune=sandybridge))
++ cflags-$(CONFIG_MIVYBRIDGE) += \
++ $(call cc-option,-march=ivybridge,$(call cc-option,-mtune=ivybridge))
++ cflags-$(CONFIG_MHASWELL) += \
++ $(call cc-option,-march=haswell,$(call cc-option,-mtune=haswell))
++ cflags-$(CONFIG_MBROADWELL) += \
++ $(call cc-option,-march=broadwell,$(call cc-option,-mtune=broadwell))
++ cflags-$(CONFIG_MSKYLAKE) += \
++ $(call cc-option,-march=skylake,$(call cc-option,-mtune=skylake))
++ cflags-$(CONFIG_MSKYLAKEX) += \
++ $(call cc-option,-march=skylake-avx512,$(call cc-option,-mtune=skylake-avx512))
++ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=bonnell) \
++ $(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic))
+ cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic)
+ KBUILD_CFLAGS += $(cflags-y)
+
+diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
+index 1f5faf8606b4..4a3a27cedc75 100644
+--- a/arch/x86/Makefile_32.cpu
++++ b/arch/x86/Makefile_32.cpu
+@@ -23,7 +23,18 @@ cflags-$(CONFIG_MK6) += -march=k6
+ # Please note, that patches that add -march=athlon-xp and friends are pointless.
+ # They make zero difference whatsosever to performance at this time.
+ cflags-$(CONFIG_MK7) += -march=athlon
++cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native)
+ cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,-march=athlon)
++cflags-$(CONFIG_MK8SSE3) += $(call cc-option,-march=k8-sse3,-march=athlon)
++cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10,-march=athlon)
++cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona,-march=athlon)
++cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1,-march=athlon)
++cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2,-march=athlon)
++cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1,-march=athlon)
++cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2,-march=athlon)
++cflags-$(CONFIG_MSTEAMROLLER) += $(call cc-option,-march=bdver3,-march=athlon)
++cflags-$(CONFIG_MEXCAVATOR) += $(call cc-option,-march=bdver4,-march=athlon)
++cflags-$(CONFIG_MZEN) += $(call cc-option,-march=znver1,-march=athlon)
+ cflags-$(CONFIG_MCRUSOE) += -march=i686 -falign-functions=0 -falign-jumps=0 -falign-loops=0
+ cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) -falign-functions=0 -falign-jumps=0 -falign-loops=0
+ cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586)
+@@ -32,8 +43,17 @@ cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) -falign-fu
+ cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686)
+ cflags-$(CONFIG_MVIAC7) += -march=i686
+ cflags-$(CONFIG_MCORE2) += -march=i686 $(call tune,core2)
+-cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march=core2,-march=i686)) \
+- $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
++cflags-$(CONFIG_MNEHALEM) += -march=i686 $(call tune,nehalem)
++cflags-$(CONFIG_MWESTMERE) += -march=i686 $(call tune,westmere)
++cflags-$(CONFIG_MSILVERMONT) += -march=i686 $(call tune,silvermont)
++cflags-$(CONFIG_MSANDYBRIDGE) += -march=i686 $(call tune,sandybridge)
++cflags-$(CONFIG_MIVYBRIDGE) += -march=i686 $(call tune,ivybridge)
++cflags-$(CONFIG_MHASWELL) += -march=i686 $(call tune,haswell)
++cflags-$(CONFIG_MBROADWELL) += -march=i686 $(call tune,broadwell)
++cflags-$(CONFIG_MSKYLAKE) += -march=i686 $(call tune,skylake)
++cflags-$(CONFIG_MSKYLAKEX) += -march=i686 $(call tune,skylake-avx512)
++cflags-$(CONFIG_MATOM) += $(call cc-option,-march=bonnell,$(call cc-option,-march=core2,-march=i686)) \
++ $(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic))
+
+ # AMD Elan support
+ cflags-$(CONFIG_MELAN) += -march=i486
+diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h
+index 7948a17febb4..22c53c8b844b 100644
+--- a/arch/x86/include/asm/module.h
++++ b/arch/x86/include/asm/module.h
+@@ -25,6 +25,26 @@ struct mod_arch_specific {
+ #define MODULE_PROC_FAMILY "586MMX "
+ #elif defined CONFIG_MCORE2
+ #define MODULE_PROC_FAMILY "CORE2 "
++#elif defined CONFIG_MNATIVE
++#define MODULE_PROC_FAMILY "NATIVE "
++#elif defined CONFIG_MNEHALEM
++#define MODULE_PROC_FAMILY "NEHALEM "
++#elif defined CONFIG_MWESTMERE
++#define MODULE_PROC_FAMILY "WESTMERE "
++#elif defined CONFIG_MSILVERMONT
++#define MODULE_PROC_FAMILY "SILVERMONT "
++#elif defined CONFIG_MSANDYBRIDGE
++#define MODULE_PROC_FAMILY "SANDYBRIDGE "
++#elif defined CONFIG_MIVYBRIDGE
++#define MODULE_PROC_FAMILY "IVYBRIDGE "
++#elif defined CONFIG_MHASWELL
++#define MODULE_PROC_FAMILY "HASWELL "
++#elif defined CONFIG_MBROADWELL
++#define MODULE_PROC_FAMILY "BROADWELL "
++#elif defined CONFIG_MSKYLAKE
++#define MODULE_PROC_FAMILY "SKYLAKE "
++#elif defined CONFIG_MSKYLAKEX
++#define MODULE_PROC_FAMILY "SKYLAKEX "
+ #elif defined CONFIG_MATOM
+ #define MODULE_PROC_FAMILY "ATOM "
+ #elif defined CONFIG_M686
+@@ -43,6 +63,26 @@ struct mod_arch_specific {
+ #define MODULE_PROC_FAMILY "K7 "
+ #elif defined CONFIG_MK8
+ #define MODULE_PROC_FAMILY "K8 "
++#elif defined CONFIG_MK8SSE3
++#define MODULE_PROC_FAMILY "K8SSE3 "
++#elif defined CONFIG_MK10
++#define MODULE_PROC_FAMILY "K10 "
++#elif defined CONFIG_MBARCELONA
++#define MODULE_PROC_FAMILY "BARCELONA "
++#elif defined CONFIG_MBOBCAT
++#define MODULE_PROC_FAMILY "BOBCAT "
++#elif defined CONFIG_MBULLDOZER
++#define MODULE_PROC_FAMILY "BULLDOZER "
++#elif defined CONFIG_MPILEDRIVER
++#define MODULE_PROC_FAMILY "PILEDRIVER "
++#elif defined CONFIG_MSTEAMROLLER
++#define MODULE_PROC_FAMILY "STEAMROLLER "
++#elif defined CONFIG_MJAGUAR
++#define MODULE_PROC_FAMILY "JAGUAR "
++#elif defined CONFIG_MEXCAVATOR
++#define MODULE_PROC_FAMILY "EXCAVATOR "
++#elif defined CONFIG_MZEN
++#define MODULE_PROC_FAMILY "ZEN "
+ #elif defined CONFIG_MELAN
+ #define MODULE_PROC_FAMILY "ELAN "
+ #elif defined CONFIG_MCRUSOE
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0001-arm-partially-revert-702b94bff3c50542a6e4ab9a4f4cef0.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0001-arm-partially-revert-702b94bff3c50542a6e4ab9a4f4cef0.patch
new file mode 100644
index 00000000..99dd3a33
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0001-arm-partially-revert-702b94bff3c50542a6e4ab9a4f4cef0.patch
@@ -0,0 +1,107 @@
+From a85a48f170d8ca4be05489f7c08440fdfed23a88 Mon Sep 17 00:00:00 2001
+From: Dan Pasanen <dan.pasanen@gmail.com>
+Date: Thu, 21 Sep 2017 09:55:42 -0500
+Subject: [PATCH 001/185] arm: partially revert
+ 702b94bff3c50542a6e4ab9a4f4cef093262fe65
+
+* Re-expose some dmi APIs for use in VCSM
+---
+ arch/arm/include/asm/cacheflush.h | 21 +++++++++++++++++++++
+ arch/arm/include/asm/glue-cache.h | 2 ++
+ arch/arm/mm/proc-macros.S | 2 ++
+ arch/arm/mm/proc-syms.c | 3 +++
+ 4 files changed, 28 insertions(+)
+
+diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
+index ec1a5fd0d294..dc0a32fdde43 100644
+--- a/arch/arm/include/asm/cacheflush.h
++++ b/arch/arm/include/asm/cacheflush.h
+@@ -94,6 +94,21 @@
+ * DMA Cache Coherency
+ * ===================
+ *
++ * dma_inv_range(start, end)
++ *
++ * Invalidate (discard) the specified virtual address range.
++ * May not write back any entries. If 'start' or 'end'
++ * are not cache line aligned, those lines must be written
++ * back.
++ * - start - virtual start address
++ * - end - virtual end address
++ *
++ * dma_clean_range(start, end)
++ *
++ * Clean (write back) the specified virtual address range.
++ * - start - virtual start address
++ * - end - virtual end address
++ *
+ * dma_flush_range(start, end)
+ *
+ * Clean and invalidate the specified virtual address range.
+@@ -115,6 +130,8 @@ struct cpu_cache_fns {
+ void (*dma_map_area)(const void *, size_t, int);
+ void (*dma_unmap_area)(const void *, size_t, int);
+
++ void (*dma_inv_range)(const void *, const void *);
++ void (*dma_clean_range)(const void *, const void *);
+ void (*dma_flush_range)(const void *, const void *);
+ } __no_randomize_layout;
+
+@@ -140,6 +157,8 @@ extern struct cpu_cache_fns cpu_cache;
+ * is visible to DMA, or data written by DMA to system memory is
+ * visible to the CPU.
+ */
++#define dmac_inv_range cpu_cache.dma_inv_range
++#define dmac_clean_range cpu_cache.dma_clean_range
+ #define dmac_flush_range cpu_cache.dma_flush_range
+
+ #else
+@@ -159,6 +178,8 @@ extern void __cpuc_flush_dcache_area(void *, size_t);
+ * is visible to DMA, or data written by DMA to system memory is
+ * visible to the CPU.
+ */
++extern void dmac_inv_range(const void *, const void *);
++extern void dmac_clean_range(const void *, const void *);
+ extern void dmac_flush_range(const void *, const void *);
+
+ #endif
+diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
+index 8d1f498e5dd8..0050d2246da8 100644
+--- a/arch/arm/include/asm/glue-cache.h
++++ b/arch/arm/include/asm/glue-cache.h
+@@ -158,6 +158,8 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { }
+ #define __cpuc_coherent_user_range __glue(_CACHE,_coherent_user_range)
+ #define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area)
+
++#define dmac_inv_range __glue(_CACHE,_dma_inv_range)
++#define dmac_clean_range __glue(_CACHE,_dma_clean_range)
+ #define dmac_flush_range __glue(_CACHE,_dma_flush_range)
+ #endif
+
+diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
+index 5461d589a1e2..8d1d479a86fa 100644
+--- a/arch/arm/mm/proc-macros.S
++++ b/arch/arm/mm/proc-macros.S
+@@ -335,6 +335,8 @@ ENTRY(\name\()_cache_fns)
+ .long \name\()_flush_kern_dcache_area
+ .long \name\()_dma_map_area
+ .long \name\()_dma_unmap_area
++ .long \name\()_dma_inv_range
++ .long \name\()_dma_clean_range
+ .long \name\()_dma_flush_range
+ .size \name\()_cache_fns, . - \name\()_cache_fns
+ .endm
+diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
+index 054b491ff764..70e8b7d34434 100644
+--- a/arch/arm/mm/proc-syms.c
++++ b/arch/arm/mm/proc-syms.c
+@@ -30,6 +30,9 @@ EXPORT_SYMBOL(__cpuc_flush_user_all);
+ EXPORT_SYMBOL(__cpuc_flush_user_range);
+ EXPORT_SYMBOL(__cpuc_coherent_kern_range);
+ EXPORT_SYMBOL(__cpuc_flush_dcache_area);
++EXPORT_SYMBOL(dmac_inv_range);
++EXPORT_SYMBOL(dmac_clean_range);
++EXPORT_SYMBOL(dmac_flush_range);
+ #else
+ EXPORT_SYMBOL(cpu_cache);
+ #endif
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0002-Revert-rtc-pcf8523-properly-handle-oscillator-stop-b.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0002-Revert-rtc-pcf8523-properly-handle-oscillator-stop-b.patch
new file mode 100644
index 00000000..b54d5072
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0002-Revert-rtc-pcf8523-properly-handle-oscillator-stop-b.patch
@@ -0,0 +1,58 @@
+From 3e80952340de5acb9650633e2dc4f0468444e99e Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 29 Oct 2018 14:45:45 +0000
+Subject: [PATCH 002/185] Revert "rtc: pcf8523: properly handle oscillator stop
+ bit"
+
+This reverts commit ede44c908d44b166a5b6bd7caacd105c2ff5a70f.
+
+See: https://github.com/raspberrypi/firmware/issues/1065
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/rtc/rtc-pcf8523.c | 25 ++++++++++++++++++++++---
+ 1 file changed, 22 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
+index b5c61a70b5df..7e1d48347b3f 100644
+--- a/drivers/rtc/rtc-pcf8523.c
++++ b/drivers/rtc/rtc-pcf8523.c
+@@ -212,8 +212,28 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)
+ if (err < 0)
+ return err;
+
+- if (regs[0] & REG_SECONDS_OS)
+- return -EINVAL;
++ if (regs[0] & REG_SECONDS_OS) {
++ /*
++ * If the oscillator was stopped, try to clear the flag. Upon
++ * power-up the flag is always set, but if we cannot clear it
++ * the oscillator isn't running properly for some reason. The
++ * sensible thing therefore is to return an error, signalling
++ * that the clock cannot be assumed to be correct.
++ */
++
++ regs[0] &= ~REG_SECONDS_OS;
++
++ err = pcf8523_write(client, REG_SECONDS, regs[0]);
++ if (err < 0)
++ return err;
++
++ err = pcf8523_read(client, REG_SECONDS, &regs[0]);
++ if (err < 0)
++ return err;
++
++ if (regs[0] & REG_SECONDS_OS)
++ return -EAGAIN;
++ }
+
+ tm->tm_sec = bcd2bin(regs[0] & 0x7f);
+ tm->tm_min = bcd2bin(regs[1] & 0x7f);
+@@ -249,7 +269,6 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
+ return err;
+
+ regs[0] = REG_SECONDS;
+- /* This will purposely overwrite REG_SECONDS_OS */
+ regs[1] = bin2bcd(tm->tm_sec);
+ regs[2] = bin2bcd(tm->tm_min);
+ regs[3] = bin2bcd(tm->tm_hour);
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0003-smsx95xx-fix-crimes-against-truesize.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0003-smsx95xx-fix-crimes-against-truesize.patch
new file mode 100644
index 00000000..380c388f
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0003-smsx95xx-fix-crimes-against-truesize.patch
@@ -0,0 +1,49 @@
+From dbbe485ba8a3cb95402b9a423a7fc0fd4dac58c9 Mon Sep 17 00:00:00 2001
+From: Steve Glendinning <steve.glendinning@smsc.com>
+Date: Thu, 19 Feb 2015 18:47:12 +0000
+Subject: [PATCH 003/185] smsx95xx: fix crimes against truesize
+
+smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings.
+
+This patch stops smsc95xx from changing truesize.
+
+Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
+---
+ drivers/net/usb/smsc95xx.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
+index e3d08626828e..3d6276566a13 100644
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -82,6 +82,10 @@ static bool turbo_mode = true;
+ module_param(turbo_mode, bool, 0644);
+ MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+
++static bool truesize_mode = false;
++module_param(truesize_mode, bool, 0644);
++MODULE_PARM_DESC(truesize_mode, "Report larger truesize value");
++
+ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
+ u32 *data, int in_pm)
+ {
+@@ -1969,7 +1973,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+ if (dev->net->features & NETIF_F_RXCSUM)
+ smsc95xx_rx_csum_offload(skb);
+ skb_trim(skb, skb->len - 4); /* remove fcs */
+- skb->truesize = size + sizeof(struct sk_buff);
++ if (truesize_mode)
++ skb->truesize = size + sizeof(struct sk_buff);
+
+ return 1;
+ }
+@@ -1987,7 +1992,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+ if (dev->net->features & NETIF_F_RXCSUM)
+ smsc95xx_rx_csum_offload(ax_skb);
+ skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
+- ax_skb->truesize = size + sizeof(struct sk_buff);
++ if (truesize_mode)
++ ax_skb->truesize = size + sizeof(struct sk_buff);
+
+ usbnet_skb_return(dev, ax_skb);
+ }
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0004-smsc95xx-Experimental-Enable-turbo_mode-and-packetsi.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0004-smsc95xx-Experimental-Enable-turbo_mode-and-packetsi.patch
new file mode 100644
index 00000000..0c3bd6f1
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0004-smsc95xx-Experimental-Enable-turbo_mode-and-packetsi.patch
@@ -0,0 +1,45 @@
+From bc9e08d983b25131ed7b07c83a2e6579564dfb82 Mon Sep 17 00:00:00 2001
+From: Sam Nazarko <email@samnazarko.co.uk>
+Date: Fri, 1 Apr 2016 17:27:21 +0100
+Subject: [PATCH 004/185] smsc95xx: Experimental: Enable turbo_mode and
+ packetsize=2560 by default
+
+See: http://forum.kodi.tv/showthread.php?tid=285288
+---
+ drivers/net/usb/smsc95xx.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
+index 3d6276566a13..df3c6bd751bf 100644
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -86,6 +86,10 @@ static bool truesize_mode = false;
+ module_param(truesize_mode, bool, 0644);
+ MODULE_PARM_DESC(truesize_mode, "Report larger truesize value");
+
++static int packetsize = 2560;
++module_param(packetsize, int, 0644);
++MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
++
+ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
+ u32 *data, int in_pm)
+ {
+@@ -1107,13 +1111,13 @@ static int smsc95xx_reset(struct usbnet *dev)
+
+ if (!turbo_mode) {
+ burst_cap = 0;
+- dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
++ dev->rx_urb_size = packetsize ? packetsize : MAX_SINGLE_PACKET_SIZE;
+ } else if (dev->udev->speed == USB_SPEED_HIGH) {
+- burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
+- dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
++ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_HS_BURST_CAP_SIZE;
++ burst_cap = dev->rx_urb_size / HS_USB_PKT_SIZE;
+ } else {
+- burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+- dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
++ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_FS_BURST_CAP_SIZE;
++ burst_cap = dev->rx_urb_size / FS_USB_PKT_SIZE;
+ }
+
+ netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n",
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0005-Allow-mac-address-to-be-set-in-smsc95xx.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0005-Allow-mac-address-to-be-set-in-smsc95xx.patch
new file mode 100644
index 00000000..400a7d1c
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0005-Allow-mac-address-to-be-set-in-smsc95xx.patch
@@ -0,0 +1,98 @@
+From 3844311bfed242be35b3181f1dce24c1ab4a8261 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 26 Mar 2013 17:26:38 +0000
+Subject: [PATCH 005/185] Allow mac address to be set in smsc95xx
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+---
+ drivers/net/usb/smsc95xx.c | 56 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 56 insertions(+)
+
+diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
+index df3c6bd751bf..2dd5f72ad8b1 100644
+--- a/drivers/net/usb/smsc95xx.c
++++ b/drivers/net/usb/smsc95xx.c
+@@ -60,6 +60,7 @@
+ #define SUSPEND_SUSPEND3 (0x08)
+ #define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
+ SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
++#define MAC_ADDR_LEN (6)
+
+ #define CARRIER_CHECK_DELAY (2 * HZ)
+
+@@ -90,6 +91,10 @@ static int packetsize = 2560;
+ module_param(packetsize, int, 0644);
+ MODULE_PARM_DESC(packetsize, "Override the RX URB packet size");
+
++static char *macaddr = ":";
++module_param(macaddr, charp, 0);
++MODULE_PARM_DESC(macaddr, "MAC address");
++
+ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
+ u32 *data, int in_pm)
+ {
+@@ -919,6 +924,53 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+ }
+
++/* Check the macaddr module parameter for a MAC address */
++static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
++{
++ int i, j, got_num, num;
++ u8 mtbl[MAC_ADDR_LEN];
++
++ if (macaddr[0] == ':')
++ return 0;
++
++ i = 0;
++ j = 0;
++ num = 0;
++ got_num = 0;
++ while (j < MAC_ADDR_LEN) {
++ if (macaddr[i] && macaddr[i] != ':') {
++ got_num++;
++ if ('0' <= macaddr[i] && macaddr[i] <= '9')
++ num = num * 16 + macaddr[i] - '0';
++ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
++ num = num * 16 + 10 + macaddr[i] - 'A';
++ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
++ num = num * 16 + 10 + macaddr[i] - 'a';
++ else
++ break;
++ i++;
++ } else if (got_num == 2) {
++ mtbl[j++] = (u8) num;
++ num = 0;
++ got_num = 0;
++ i++;
++ } else {
++ break;
++ }
++ }
++
++ if (j == MAC_ADDR_LEN) {
++ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
++ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
++ mtbl[3], mtbl[4], mtbl[5]);
++ for (i = 0; i < MAC_ADDR_LEN; i++)
++ dev_mac[i] = mtbl[i];
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
+ static void smsc95xx_init_mac_address(struct usbnet *dev)
+ {
+ const u8 *mac_addr;
+@@ -940,6 +992,10 @@ static void smsc95xx_init_mac_address(struct usbnet *dev)
+ }
+ }
+
++ /* Check module parameters */
++ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
++ return;
++
+ /* no useful static MAC address found. generate a random one */
+ eth_hw_addr_random(dev->net);
+ netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n");
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0006-Protect-__release_resource-against-resources-without.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0006-Protect-__release_resource-against-resources-without.patch
new file mode 100644
index 00000000..2b8a1582
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0006-Protect-__release_resource-against-resources-without.patch
@@ -0,0 +1,30 @@
+From b3d18c9fd4d6303968cf26a2dfc3f0d10e68fd4f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 13 Mar 2015 12:43:36 +0000
+Subject: [PATCH 006/185] Protect __release_resource against resources without
+ parents
++
+Without this patch, removing a device tree overlay can crash here.
++
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ kernel/resource.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
++
+diff --git a/kernel/resource.c b/kernel/resource.c
+index 92190f62ebc5..ac6b7ede9a7a 100644
+--- a/kernel/resource.c
++++ b/kernel/resource.c
+@@ -213,6 +213,12 @@ static int __release_resource(struct resource *old, bool release_child)
+ {
+ struct resource *tmp, **p, *chd;
+
++ if (!old->parent) {
++ WARN(old->sibling, "sibling but no parent");
++ if (old->sibling)
++ return -EINVAL;
++ return 0;
++ }
+ p = &old->parent->child;
+ for (;;) {
+ tmp = *p;
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0007-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0007-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch
new file mode 100644
index 00000000..73a68179
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0007-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch
@@ -0,0 +1,29 @@
+From 66cc96845cded65d926e07528802815ed6c8f3d5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 4 Dec 2015 17:41:50 +0000
+Subject: [PATCH 007/185] irq-bcm2836: Prevent spurious interrupts, and trap
+ them early
+
+The old arch-specific IRQ macros included a dsb to ensure the
+write to clear the mailbox interrupt completed before returning
+from the interrupt. The BCM2836 irqchip driver needs the same
+precaution to avoid spurious interrupts.
+
+Spurious interrupts are still possible for other reasons,
+though, so trap them early.
+---
+ drivers/irqchip/irq-bcm2836.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
+index 2038693f074c..597d36ba601e 100644
+--- a/drivers/irqchip/irq-bcm2836.c
++++ b/drivers/irqchip/irq-bcm2836.c
+@@ -135,6 +135,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
+ u32 ipi = ffs(mbox_val) - 1;
+
+ writel(1 << ipi, mailbox0);
++ dsb(sy);
+ handle_IPI(ipi, regs);
+ #endif
+ } else if (stat) {
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0008-irq-bcm2836-Avoid-Invalid-trigger-warning.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0008-irq-bcm2836-Avoid-Invalid-trigger-warning.patch
new file mode 100644
index 00000000..be6d8f36
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0008-irq-bcm2836-Avoid-Invalid-trigger-warning.patch
@@ -0,0 +1,26 @@
+From 835f6e8d1bcb80c420b20681976771e0edfe2a37 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 9 Feb 2017 14:33:30 +0000
+Subject: [PATCH 008/185] irq-bcm2836: Avoid "Invalid trigger warning"
+
+Initialise the level for each IRQ to avoid a warning from the
+arm arch timer code.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/irqchip/irq-bcm2836.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
+index 597d36ba601e..c006a8ac10d5 100644
+--- a/drivers/irqchip/irq-bcm2836.c
++++ b/drivers/irqchip/irq-bcm2836.c
+@@ -115,7 +115,7 @@ static int bcm2836_map(struct irq_domain *d, unsigned int irq,
+ irq_set_percpu_devid(irq);
+ irq_domain_set_info(d, irq, hw, chip, d->host_data,
+ handle_percpu_devid_irq, NULL, NULL);
+- irq_set_status_flags(irq, IRQ_NOAUTOEN);
++ irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW);
+
+ return 0;
+ }
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0009-irqchip-bcm2835-Add-FIQ-support.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0009-irqchip-bcm2835-Add-FIQ-support.patch
new file mode 100644
index 00000000..e3dcf052
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0009-irqchip-bcm2835-Add-FIQ-support.patch
@@ -0,0 +1,131 @@
+From 83fac9874db9dd333f23efe250f8f5c857df93f1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 12 Jun 2015 19:01:05 +0200
+Subject: [PATCH 009/185] irqchip: bcm2835: Add FIQ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a duplicate irq range with an offset on the hwirq's so the
+driver can detect that enable_fiq() is used.
+Tested with downstream dwc_otg USB controller driver.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+Reviewed-by: Eric Anholt <eric@anholt.net>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+---
+ arch/arm/mach-bcm/Kconfig | 1 +
+ drivers/irqchip/irq-bcm2835.c | 51 +++++++++++++++++++++++++++++++----
+ 2 files changed, 47 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
+index 4ef1e55f4a0b..c464f2258c3f 100644
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -165,6 +165,7 @@ config ARCH_BCM2835
+ select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7
+ select TIMER_OF
+ select BCM2835_TIMER
++ select FIQ
+ select PINCTRL
+ select PINCTRL_BCM2835
+ select MFD_CORE
+diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
+index 418245d31921..64472b25d0b4 100644
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -45,7 +45,7 @@
+ #include <asm/exception.h>
+
+ /* Put the bank and irq (32 bits) into the hwirq */
+-#define MAKE_HWIRQ(b, n) ((b << 5) | (n))
++#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
+ #define HWIRQ_BANK(i) (i >> 5)
+ #define HWIRQ_BIT(i) BIT(i & 0x1f)
+
+@@ -61,9 +61,13 @@
+ | SHORTCUT1_MASK | SHORTCUT2_MASK)
+
+ #define REG_FIQ_CONTROL 0x0c
++#define REG_FIQ_ENABLE 0x80
++#define REG_FIQ_DISABLE 0
+
+ #define NR_BANKS 3
+ #define IRQS_PER_BANK 32
++#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
++#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
+
+ static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
+ static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
+@@ -88,14 +92,38 @@ static void __exception_irq_entry bcm2835_handle_irq(
+ struct pt_regs *regs);
+ static void bcm2836_chained_handle_irq(struct irq_desc *desc);
+
++static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
++{
++ hwirq -= NUMBER_IRQS;
++ /*
++ * The hwirq numbering used in this driver is:
++ * BASE (0-7) GPU1 (32-63) GPU2 (64-95).
++ * This differ from the one used in the FIQ register:
++ * GPU1 (0-31) GPU2 (32-63) BASE (64-71)
++ */
++ if (hwirq >= 32)
++ return hwirq - 32;
++
++ return hwirq + 64;
++}
++
+ static void armctrl_mask_irq(struct irq_data *d)
+ {
+- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
++ if (d->hwirq >= NUMBER_IRQS)
++ writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
++ else
++ writel_relaxed(HWIRQ_BIT(d->hwirq),
++ intc.disable[HWIRQ_BANK(d->hwirq)]);
+ }
+
+ static void armctrl_unmask_irq(struct irq_data *d)
+ {
+- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
++ if (d->hwirq >= NUMBER_IRQS)
++ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
++ intc.base + REG_FIQ_CONTROL);
++ else
++ writel_relaxed(HWIRQ_BIT(d->hwirq),
++ intc.enable[HWIRQ_BANK(d->hwirq)]);
+ }
+
+ static struct irq_chip armctrl_chip = {
+@@ -140,8 +168,9 @@ static int __init armctrl_of_init(struct device_node *node,
+ if (!base)
+ panic("%pOF: unable to map IC registers\n", node);
+
+- intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
+- &armctrl_ops, NULL);
++ intc.base = base;
++ intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
++ &armctrl_ops, NULL);
+ if (!intc.domain)
+ panic("%pOF: unable to create IRQ domain\n", node);
+
+@@ -171,6 +200,18 @@ static int __init armctrl_of_init(struct device_node *node,
+ set_handle_irq(bcm2835_handle_irq);
+ }
+
++ /* Make a duplicate irq range which is used to enable FIQ */
++ for (b = 0; b < NR_BANKS; b++) {
++ for (i = 0; i < bank_irqs[b]; i++) {
++ irq = irq_create_mapping(intc.domain,
++ MAKE_HWIRQ(b, i) + NUMBER_IRQS);
++ BUG_ON(irq <= 0);
++ irq_set_chip(irq, &armctrl_chip);
++ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++ }
++ }
++ init_FIQ(FIQ_START);
++
+ return 0;
+ }
+
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0010-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0010-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch
new file mode 100644
index 00000000..6fec39b6
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0010-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch
@@ -0,0 +1,101 @@
+From 3d4c6857e4908e313374afca2ab76d53ec646d54 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 23 Oct 2015 16:26:55 +0200
+Subject: [PATCH 010/185] irqchip: irq-bcm2835: Add 2836 FIQ support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/irqchip/irq-bcm2835.c | 43 +++++++++++++++++++++++++++++++++--
+ 1 file changed, 41 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
+index 64472b25d0b4..2fccc5cfe9f3 100644
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -41,8 +41,11 @@
+ #include <linux/of_irq.h>
+ #include <linux/irqchip.h>
+ #include <linux/irqdomain.h>
++#include <linux/mfd/syscon.h>
++#include <linux/regmap.h>
+
+ #include <asm/exception.h>
++#include <asm/mach/irq.h>
+
+ /* Put the bank and irq (32 bits) into the hwirq */
+ #define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
+@@ -60,6 +63,9 @@
+ #define BANK0_VALID_MASK (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
+ | SHORTCUT1_MASK | SHORTCUT2_MASK)
+
++#undef ARM_LOCAL_GPU_INT_ROUTING
++#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
++
+ #define REG_FIQ_CONTROL 0x0c
+ #define REG_FIQ_ENABLE 0x80
+ #define REG_FIQ_DISABLE 0
+@@ -85,6 +91,7 @@ struct armctrl_ic {
+ void __iomem *enable[NR_BANKS];
+ void __iomem *disable[NR_BANKS];
+ struct irq_domain *domain;
++ struct regmap *local_regmap;
+ };
+
+ static struct armctrl_ic intc __read_mostly;
+@@ -118,12 +125,35 @@ static void armctrl_mask_irq(struct irq_data *d)
+
+ static void armctrl_unmask_irq(struct irq_data *d)
+ {
+- if (d->hwirq >= NUMBER_IRQS)
++ if (d->hwirq >= NUMBER_IRQS) {
++ if (num_online_cpus() > 1) {
++ unsigned int data;
++ int ret;
++
++ if (!intc.local_regmap) {
++ pr_err("FIQ is disabled due to missing regmap\n");
++ return;
++ }
++
++ ret = regmap_read(intc.local_regmap,
++ ARM_LOCAL_GPU_INT_ROUTING, &data);
++ if (ret) {
++ pr_err("Failed to read int routing %d\n", ret);
++ return;
++ }
++
++ data &= ~0xc;
++ data |= (1 << 2);
++ regmap_write(intc.local_regmap,
++ ARM_LOCAL_GPU_INT_ROUTING, data);
++ }
++
+ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
+ intc.base + REG_FIQ_CONTROL);
+- else
++ } else {
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
+ intc.enable[HWIRQ_BANK(d->hwirq)]);
++ }
+ }
+
+ static struct irq_chip armctrl_chip = {
+@@ -200,6 +230,15 @@ static int __init armctrl_of_init(struct device_node *node,
+ set_handle_irq(bcm2835_handle_irq);
+ }
+
++ if (is_2836) {
++ intc.local_regmap =
++ syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
++ if (IS_ERR(intc.local_regmap)) {
++ pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
++ intc.local_regmap = NULL;
++ }
++ }
++
+ /* Make a duplicate irq range which is used to enable FIQ */
+ for (b = 0; b < NR_BANKS; b++) {
+ for (i = 0; i < bank_irqs[b]; i++) {
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0011-spi-spidev-Completely-disable-the-spidev-warning.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0011-spi-spidev-Completely-disable-the-spidev-warning.patch
new file mode 100644
index 00000000..ea65eba2
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0011-spi-spidev-Completely-disable-the-spidev-warning.patch
@@ -0,0 +1,26 @@
+From 91bafc356d9c47c9c29bc6c315f79206a1660c8c Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 14 Jul 2015 10:26:09 +0100
+Subject: [PATCH 011/185] spi: spidev: Completely disable the spidev warning
+
+An alternative strategy would be to use "rpi,spidev" instead, but that
+would require many Raspberry Pi Device Tree changes.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/spi/spidev.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
+index b0c76e2626ce..b0657fdfe171 100644
+--- a/drivers/spi/spidev.c
++++ b/drivers/spi/spidev.c
+@@ -725,7 +725,7 @@ static int spidev_probe(struct spi_device *spi)
+ * compatible string, it is a Linux implementation thing
+ * rather than a description of the hardware.
+ */
+- WARN(spi->dev.of_node &&
++ WARN(0 && spi->dev.of_node &&
+ of_device_is_compatible(spi->dev.of_node, "spidev"),
+ "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
+
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0012-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0012-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch
new file mode 100644
index 00000000..059317e5
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0012-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch
@@ -0,0 +1,105 @@
+From 0686654df18e1156e0a81c1e8305470650939db9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Sat, 3 Oct 2015 22:22:55 +0200
+Subject: [PATCH 012/185] dmaengine: bcm2835: Load driver early and support
+ legacy API
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Load driver early since at least bcm2708_fb doesn't support deferred
+probing and even if it did, we don't want the video driver deferred.
+Support the legacy DMA API which is needed by bcm2708_fb.
+Don't mask out channel 2.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/dma/Kconfig | 2 +-
+ drivers/dma/bcm2835-dma.c | 26 +++++++++++++++++++++++++-
+ 2 files changed, 26 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
+index 0b1dfb5bf2d9..e49f1f5372a7 100644
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -131,7 +131,7 @@ config COH901318
+
+ config DMA_BCM2835
+ tristate "BCM2835 DMA engine support"
+- depends on ARCH_BCM2835
++ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+
+diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
+index 54093ffd0aef..44fb5ff5da4d 100644
+--- a/drivers/dma/bcm2835-dma.c
++++ b/drivers/dma/bcm2835-dma.c
+@@ -25,6 +25,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/list.h>
+ #include <linux/module.h>
++#include <linux/platform_data/dma-bcm2708.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <linux/io.h>
+@@ -36,6 +37,7 @@
+
+ #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
+ #define BCM2835_DMA_CHAN_NAME_SIZE 8
++#define BCM2835_DMA_BULK_MASK BIT(0)
+
+ struct bcm2835_dmadev {
+ struct dma_device ddev;
+@@ -885,6 +887,9 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
++ rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
++ if (rc)
++ dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
+
+ od->base = base;
+
+@@ -922,6 +927,9 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
+ goto err_no_dma;
+ }
+
++ /* Channel 0 is used by the legacy API */
++ chans_available &= ~BCM2835_DMA_BULK_MASK;
++
+ /* get irqs for each channel that we support */
+ for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) {
+ /* skip masked out channels */
+@@ -996,6 +1004,7 @@ static int bcm2835_dma_remove(struct platform_device *pdev)
+ {
+ struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
+
++ bcm_dmaman_remove(pdev);
+ dma_async_device_unregister(&od->ddev);
+ bcm2835_dma_free(od);
+
+@@ -1011,7 +1020,22 @@ static struct platform_driver bcm2835_dma_driver = {
+ },
+ };
+
+-module_platform_driver(bcm2835_dma_driver);
++static int bcm2835_dma_init(void)
++{
++ return platform_driver_register(&bcm2835_dma_driver);
++}
++
++static void bcm2835_dma_exit(void)
++{
++ platform_driver_unregister(&bcm2835_dma_driver);
++}
++
++/*
++ * Load after serial driver (arch_initcall) so we see the messages if it fails,
++ * but before drivers (module_init) that need a DMA channel.
++ */
++subsys_initcall(bcm2835_dma_init);
++module_exit(bcm2835_dma_exit);
+
+ MODULE_ALIAS("platform:bcm2835-dma");
+ MODULE_DESCRIPTION("BCM2835 DMA engine driver");
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0013-firmware-Updated-mailbox-header.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0013-firmware-Updated-mailbox-header.patch
new file mode 100644
index 00000000..2c072607
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0013-firmware-Updated-mailbox-header.patch
@@ -0,0 +1,29 @@
+From ab4735043e8756947c6480c404e019ae7816c05c Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Mon, 25 Jan 2016 17:25:12 +0000
+Subject: [PATCH 013/185] firmware: Updated mailbox header
+
+---
+ include/soc/bcm2835/raspberrypi-firmware.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
+index 7800e12ee042..3f357c05788e 100644
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -9,6 +9,8 @@
+ #include <linux/types.h>
+ #include <linux/of_device.h>
+
++#define RPI_FIRMWARE_CHAN_FB 1
++
+ struct rpi_firmware;
+
+ enum rpi_firmware_property_status {
+@@ -159,5 +161,6 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware
+ return NULL;
+ }
+ #endif
++int rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data);
+
+ #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0014-rtc-Add-SPI-alias-for-pcf2123-driver.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0014-rtc-Add-SPI-alias-for-pcf2123-driver.patch
new file mode 100644
index 00000000..dc807d1e
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0014-rtc-Add-SPI-alias-for-pcf2123-driver.patch
@@ -0,0 +1,22 @@
+From e210d272bfed9c7cfc7159546bdf6681fb16a570 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 15 Jun 2016 16:48:41 +0100
+Subject: [PATCH 014/185] rtc: Add SPI alias for pcf2123 driver
+
+Without this alias, Device Tree won't cause the driver
+to be loaded.
+
+See: https://github.com/raspberrypi/linux/pull/1510
+---
+ drivers/rtc/rtc-pcf2123.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
+index 39da8b214275..849e1ccd97ab 100644
+--- a/drivers/rtc/rtc-pcf2123.c
++++ b/drivers/rtc/rtc-pcf2123.c
+@@ -473,3 +473,4 @@ module_spi_driver(pcf2123_driver);
+ MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>");
+ MODULE_DESCRIPTION("NXP PCF2123 RTC driver");
+ MODULE_LICENSE("GPL");
++MODULE_ALIAS("spi:rtc-pcf2123");
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0015-watchdog-bcm2835-Support-setting-reboot-partition.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0015-watchdog-bcm2835-Support-setting-reboot-partition.patch
new file mode 100644
index 00000000..f67df2af
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0015-watchdog-bcm2835-Support-setting-reboot-partition.patch
@@ -0,0 +1,104 @@
+From 7f903a38ab966f8c24e7805f659ff45ea8305f90 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Fri, 7 Oct 2016 16:50:59 +0200
+Subject: [PATCH 015/185] watchdog: bcm2835: Support setting reboot partition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The Raspberry Pi firmware looks at the RSTS register to know which
+partition to boot from. The reboot syscall command
+LINUX_REBOOT_CMD_RESTART2 supports passing in a string argument.
+
+Add support for passing in a partition number 0..63 to boot from.
+Partition 63 is a special partiton indicating halt.
+If the partition doesn't exist, the firmware falls back to partition 0.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/watchdog/bcm2835_wdt.c | 49 +++++++++++++++++++---------------
+ 1 file changed, 27 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
+index 1834524ae373..4ed73194a64d 100644
+--- a/drivers/watchdog/bcm2835_wdt.c
++++ b/drivers/watchdog/bcm2835_wdt.c
+@@ -32,13 +32,7 @@
+ #define PM_RSTC_WRCFG_SET 0x00000030
+ #define PM_RSTC_WRCFG_FULL_RESET 0x00000020
+ #define PM_RSTC_RESET 0x00000102
+-
+-/*
+- * The Raspberry Pi firmware uses the RSTS register to know which partition
+- * to boot from. The partition value is spread into bits 0, 2, 4, 6, 8, 10.
+- * Partition 63 is a special partition used by the firmware to indicate halt.
+- */
+-#define PM_RSTS_RASPBERRYPI_HALT 0x555
++#define PM_RSTS_PARTITION_CLR 0xfffffaaa
+
+ #define SECS_TO_WDOG_TICKS(x) ((x) << 16)
+ #define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
+@@ -97,9 +91,24 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog)
+ return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
+ }
+
+-static void __bcm2835_restart(struct bcm2835_wdt *wdt)
++/*
++ * The Raspberry Pi firmware uses the RSTS register to know which partiton
++ * to boot from. The partiton value is spread into bits 0, 2, 4, 6, 8, 10.
++ * Partiton 63 is a special partition used by the firmware to indicate halt.
++ */
++
++static void __bcm2835_restart(struct bcm2835_wdt *wdt, u8 partition)
+ {
+- u32 val;
++ u32 val, rsts;
++
++ rsts = (partition & BIT(0)) | ((partition & BIT(1)) << 1) |
++ ((partition & BIT(2)) << 2) | ((partition & BIT(3)) << 3) |
++ ((partition & BIT(4)) << 4) | ((partition & BIT(5)) << 5);
++
++ val = readl_relaxed(wdt->base + PM_RSTS);
++ val &= PM_RSTS_PARTITION_CLR;
++ val |= PM_PASSWORD | rsts;
++ writel_relaxed(val, wdt->base + PM_RSTS);
+
+ /* use a timeout of 10 ticks (~150us) */
+ writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
+@@ -117,7 +126,13 @@ static int bcm2835_restart(struct watchdog_device *wdog,
+ {
+ struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+
+- __bcm2835_restart(wdt);
++ unsigned long long val;
++ u8 partition = 0;
++
++ if (data && !kstrtoull(data, 0, &val) && val <= 63)
++ partition = val;
++
++ __bcm2835_restart(wdt, partition);
+
+ return 0;
+ }
+@@ -152,19 +167,9 @@ static struct watchdog_device bcm2835_wdt_wdd = {
+ static void bcm2835_power_off(void)
+ {
+ struct bcm2835_wdt *wdt = bcm2835_power_off_wdt;
+- u32 val;
+
+- /*
+- * We set the watchdog hard reset bit here to distinguish this reset
+- * from the normal (full) reset. bootcode.bin will not reboot after a
+- * hard reset.
+- */
+- val = readl_relaxed(wdt->base + PM_RSTS);
+- val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT;
+- writel_relaxed(val, wdt->base + PM_RSTS);
+-
+- /* Continue with normal reset mechanism */
+- __bcm2835_restart(wdt);
++ /* Partition 63 tells the firmware that this is a halt */
++ __bcm2835_restart(wdt, 63);
+ }
+
+ static int bcm2835_wdt_probe(struct platform_device *pdev)
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0016-reboot-Use-power-off-rather-than-busy-spinning-when-.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0016-reboot-Use-power-off-rather-than-busy-spinning-when-.patch
new file mode 100644
index 00000000..4d03199e
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0016-reboot-Use-power-off-rather-than-busy-spinning-when-.patch
@@ -0,0 +1,25 @@
+From 4118e44f94fff011a67587b17415bdb83f2b12d6 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 5 Apr 2016 19:40:12 +0100
+Subject: [PATCH 016/185] reboot: Use power off rather than busy spinning when
+ halt is requested
+
+---
+ arch/arm/kernel/reboot.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
+index 3b2aa9a9fe26..0180d89a34af 100644
+--- a/arch/arm/kernel/reboot.c
++++ b/arch/arm/kernel/reboot.c
+@@ -105,9 +105,7 @@ void machine_shutdown(void)
+ */
+ void machine_halt(void)
+ {
+- local_irq_disable();
+- smp_send_stop();
+- while (1);
++ machine_power_off();
+ }
+
+ /*
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0017-bcm-Make-RASPBERRYPI_POWER-depend-on-PM.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0017-bcm-Make-RASPBERRYPI_POWER-depend-on-PM.patch
new file mode 100644
index 00000000..2d82eb1b
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0017-bcm-Make-RASPBERRYPI_POWER-depend-on-PM.patch
@@ -0,0 +1,21 @@
+From caa2276393e083703618df4fd90df0687720f1c7 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 9 Nov 2016 13:02:52 +0000
+Subject: [PATCH 017/185] bcm: Make RASPBERRYPI_POWER depend on PM
+
+---
+ drivers/soc/bcm/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
+index 03fa91fbe2da..902b496d3137 100644
+--- a/drivers/soc/bcm/Kconfig
++++ b/drivers/soc/bcm/Kconfig
+@@ -16,6 +16,7 @@ config RASPBERRYPI_POWER
+ bool "Raspberry Pi power domain driver"
+ depends on ARCH_BCM2835 || (COMPILE_TEST && OF)
+ depends on RASPBERRYPI_FIRMWARE=y
++ depends on PM
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the RPi power domains which can be enabled
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0018-Register-the-clocks-early-during-the-boot-process-so.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0018-Register-the-clocks-early-during-the-boot-process-so.patch
new file mode 100644
index 00000000..e16f6e00
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0018-Register-the-clocks-early-during-the-boot-process-so.patch
@@ -0,0 +1,47 @@
+From da89ee7a02b8ea340f3445533953955f91597d95 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Fri, 2 Sep 2016 16:45:27 +0100
+Subject: [PATCH 018/185] Register the clocks early during the boot process, so
+ that special/critical clocks can get enabled early on in the boot process
+ avoiding the risk of disabling a clock, pll_divider or pll when a claiming
+ driver fails to install propperly - maybe it needs to defer.
+
+Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 15 +++++++++++++--
+ 1 file changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index 9fcae932e082..c8f6391127b5 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2174,8 +2174,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ if (ret)
+ return ret;
+
+- return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
++ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+ &cprman->onecell);
++ if (ret)
++ return ret;
++
++ /* note that we have registered all the clocks */
++ dev_dbg(dev, "registered %d clocks\n", asize);
++
++ return 0;
+ }
+
+ static const struct of_device_id bcm2835_clk_of_match[] = {
+@@ -2192,7 +2199,11 @@ static struct platform_driver bcm2835_clk_driver = {
+ .probe = bcm2835_clk_probe,
+ };
+
+-builtin_platform_driver(bcm2835_clk_driver);
++static int __init __bcm2835_clk_driver_init(void)
++{
++ return platform_driver_register(&bcm2835_clk_driver);
++}
++core_initcall(__bcm2835_clk_driver_init);
+
+ MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+ MODULE_DESCRIPTION("BCM2835 clock driver");
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0019-bcm2835-rng-Avoid-initialising-if-already-enabled.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0019-bcm2835-rng-Avoid-initialising-if-already-enabled.patch
new file mode 100644
index 00000000..13daa639
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0019-bcm2835-rng-Avoid-initialising-if-already-enabled.patch
@@ -0,0 +1,27 @@
+From 8c3c384d9b13979e437de4db1969004c10d4a88e Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Tue, 6 Dec 2016 17:05:39 +0000
+Subject: [PATCH 019/185] bcm2835-rng: Avoid initialising if already enabled
+
+Avoids the 0x40000 cycles of warmup again if firmware has already used it
+---
+ drivers/char/hw_random/bcm2835-rng.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
+index f759790c3cdb..1b85ebcbca80 100644
+--- a/drivers/char/hw_random/bcm2835-rng.c
++++ b/drivers/char/hw_random/bcm2835-rng.c
+@@ -102,8 +102,10 @@ static int bcm2835_rng_init(struct hwrng *rng)
+ }
+
+ /* set warm-up count & enable */
+- rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
+- rng_writel(priv, RNG_RBGEN, RNG_CTRL);
++ if (!(rng_readl(priv, RNG_CTRL) & RNG_RBGEN)) {
++ rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS);
++ rng_writel(priv, RNG_RBGEN, RNG_CTRL);
++ }
+
+ return ret;
+ }
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0020-clk-bcm2835-Mark-used-PLLs-and-dividers-CRITICAL.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0020-clk-bcm2835-Mark-used-PLLs-and-dividers-CRITICAL.patch
new file mode 100644
index 00000000..c4de1a51
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0020-clk-bcm2835-Mark-used-PLLs-and-dividers-CRITICAL.patch
@@ -0,0 +1,30 @@
+From f125639ebf7121791445d7cc3d75bdcd6f9005fa Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 13 Feb 2017 17:20:08 +0000
+Subject: [PATCH 020/185] clk-bcm2835: Mark used PLLs and dividers CRITICAL
+
+The VPU configures and relies on several PLLs and dividers. Mark all
+enabled dividers and their PLLs as CRITICAL to prevent the kernel from
+switching them off.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index c8f6391127b5..0372f26540d6 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1352,6 +1352,11 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
+ divider->div.hw.init = &init;
+ divider->div.table = NULL;
+
++ if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) {
++ init.flags |= CLK_IS_CRITICAL;
++ divider->div.flags |= CLK_IS_CRITICAL;
++ }
++
+ divider->cprman = cprman;
+ divider->data = data;
+
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0021-clk-bcm2835-Add-claim-clocks-property.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0021-clk-bcm2835-Add-claim-clocks-property.patch
new file mode 100644
index 00000000..c0c3674d
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0021-clk-bcm2835-Add-claim-clocks-property.patch
@@ -0,0 +1,104 @@
+From 0a53d2a93022ef9c04217e12f8aa4e1fc756197f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 13 Feb 2017 17:20:08 +0000
+Subject: [PATCH 021/185] clk-bcm2835: Add claim-clocks property
+
+The claim-clocks property can be used to prevent PLLs and dividers
+from being marked as critical. It contains a vector of clock IDs,
+as defined by dt-bindings/clock/bcm2835.h.
+
+Use this mechanism to claim PLLD_DSI0, PLLD_DSI1, PLLH_AUX and
+PLLH_PIX for the vc4_kms_v3d driver.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 34 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 32 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index 0372f26540d6..fd381f8f43f7 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1284,6 +1284,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
+ .debug_init = bcm2835_clock_debug_init,
+ };
+
++static bool bcm2835_clk_is_claimed(const char *name);
++
+ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
+ const struct bcm2835_pll_data *data)
+ {
+@@ -1300,6 +1302,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
+ init.ops = &bcm2835_pll_clk_ops;
+ init.flags = CLK_IGNORE_UNUSED;
+
++ if (!bcm2835_clk_is_claimed(data->name))
++ init.flags |= CLK_IS_CRITICAL;
++
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return NULL;
+@@ -1353,8 +1358,10 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
+ divider->div.table = NULL;
+
+ if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) {
+- init.flags |= CLK_IS_CRITICAL;
+- divider->div.flags |= CLK_IS_CRITICAL;
++ if (!bcm2835_clk_is_claimed(data->source_pll))
++ init.flags |= CLK_IS_CRITICAL;
++ if (!bcm2835_clk_is_claimed(data->name))
++ divider->div.flags |= CLK_IS_CRITICAL;
+ }
+
+ divider->cprman = cprman;
+@@ -2106,6 +2113,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
+ .ctl_reg = CM_PERIICTL),
+ };
+
++static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)];
++
+ /*
+ * Permanently take a reference on the parent of the SDRAM clock.
+ *
+@@ -2125,6 +2134,19 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc)
+ return clk_prepare_enable(parent);
+ }
+
++static bool bcm2835_clk_is_claimed(const char *name)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) {
++ const char *clk_name = *(const char **)(clk_desc_array[i].data);
++ if (!strcmp(name, clk_name))
++ return bcm2835_clk_claimed[i];
++ }
++
++ return false;
++}
++
+ static int bcm2835_clk_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -2134,6 +2156,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ const struct bcm2835_clk_desc *desc;
+ const size_t asize = ARRAY_SIZE(clk_desc_array);
+ size_t i;
++ u32 clk_id;
+ int ret;
+
+ cprman = devm_kzalloc(dev,
+@@ -2149,6 +2172,13 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ if (IS_ERR(cprman->regs))
+ return PTR_ERR(cprman->regs);
+
++ memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
++ for (i = 0;
++ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",
++ i, &clk_id);
++ i++)
++ bcm2835_clk_claimed[clk_id]= true;
++
+ memcpy(cprman->real_parent_names, cprman_parent_names,
+ sizeof(cprman_parent_names));
+ of_clk_parent_fill(dev->of_node, cprman->real_parent_names,
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0022-clk-bcm2835-Read-max-core-clock-from-firmware.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0022-clk-bcm2835-Read-max-core-clock-from-firmware.patch
new file mode 100644
index 00000000..d0c2ef47
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0022-clk-bcm2835-Read-max-core-clock-from-firmware.patch
@@ -0,0 +1,117 @@
+From ac8fb249c01f01ab8f63f1188d08b6ddb6c14491 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 6 Mar 2017 09:06:18 +0000
+Subject: [PATCH 022/185] clk-bcm2835: Read max core clock from firmware
+
+The VPU is responsible for managing the core clock, usually under
+direction from the bcm2835-cpufreq driver but not via the clk-bcm2835
+driver. Since the core frequency can change without warning, it is
+safer to report the maximum clock rate to users of the core clock -
+I2C, SPI and the mini UART - to err on the safe side when calculating
+clock divisors.
+
+If the DT node for the clock driver includes a reference to the
+firmware node, use the firmware API to query the maximum core clock
+instead of reading the divider registers.
+
+Prior to this patch, a "100KHz" I2C bus was sometimes clocked at about
+160KHz. In particular, switching to the 4.9 kernel was likely to break
+SenseHAT usage on a Pi3.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 39 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 38 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index fd381f8f43f7..e1ceafdc7dce 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -34,6 +34,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+ #include <dt-bindings/clock/bcm2835.h>
++#include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define CM_PASSWORD 0x5a000000
+
+@@ -288,6 +289,8 @@
+ #define LOCK_TIMEOUT_NS 100000000
+ #define BCM2835_MAX_FB_RATE 1750000000u
+
++#define VCMSG_ID_CORE_CLOCK 4
++
+ /*
+ * Names of clocks used within the driver that need to be replaced
+ * with an external parent's name. This array is in the order that
+@@ -306,6 +309,7 @@ static const char *const cprman_parent_names[] = {
+ struct bcm2835_cprman {
+ struct device *dev;
+ void __iomem *regs;
++ struct rpi_firmware *fw;
+ spinlock_t regs_lock; /* spinlock for all clocks */
+
+ /*
+@@ -988,6 +992,30 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
+ return bcm2835_clock_rate_from_divisor(clock, parent_rate, div);
+ }
+
++static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
++ struct bcm2835_cprman *cprman = clock->cprman;
++
++ if (cprman->fw) {
++ struct {
++ u32 id;
++ u32 val;
++ } packet;
++
++ packet.id = VCMSG_ID_CORE_CLOCK;
++ packet.val = 0;
++
++ if (!rpi_firmware_property(cprman->fw,
++ RPI_FIRMWARE_GET_MAX_CLOCK_RATE,
++ &packet, sizeof(packet)))
++ return packet.val;
++ }
++
++ return bcm2835_clock_get_rate(hw, parent_rate);
++}
++
+ static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock)
+ {
+ struct bcm2835_cprman *cprman = clock->cprman;
+@@ -1276,7 +1304,7 @@ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
+ */
+ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
+ .is_prepared = bcm2835_vpu_clock_is_on,
+- .recalc_rate = bcm2835_clock_get_rate,
++ .recalc_rate = bcm2835_clock_get_rate_vpu,
+ .set_rate = bcm2835_clock_set_rate,
+ .determine_rate = bcm2835_clock_determine_rate,
+ .set_parent = bcm2835_clock_set_parent,
+@@ -2155,6 +2183,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ struct resource *res;
+ const struct bcm2835_clk_desc *desc;
+ const size_t asize = ARRAY_SIZE(clk_desc_array);
++ struct device_node *fw_node;
+ size_t i;
+ u32 clk_id;
+ int ret;
+@@ -2172,6 +2201,14 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
+ if (IS_ERR(cprman->regs))
+ return PTR_ERR(cprman->regs);
+
++ fw_node = of_parse_phandle(dev->of_node, "firmware", 0);
++ if (fw_node) {
++ struct rpi_firmware *fw = rpi_firmware_get(NULL);
++ if (!fw)
++ return -EPROBE_DEFER;
++ cprman->fw = fw;
++ }
++
+ memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed));
+ for (i = 0;
+ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks",
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0023-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0023-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch
new file mode 100644
index 00000000..5aef270a
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0023-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch
@@ -0,0 +1,40 @@
+From 7380ef215079d9ed80299210eac28e8a9b97aeb5 Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Mon, 9 May 2016 17:28:18 -0700
+Subject: [PATCH 023/185] clk: bcm2835: Mark GPIO clocks enabled at boot as
+ critical.
+
+These divide off of PLLD_PER and are used for the ethernet and wifi
+PHYs source PLLs. Neither of them is currently represented by a phy
+device that would grab the clock for us.
+
+This keeps other drivers from killing the networking PHYs when they
+disable their own clocks and trigger PLLD_PER's refcount going to 0.
+
+v2: Skip marking as critical if they aren't on at boot.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
+index e1ceafdc7dce..b6399a4fc53f 100644
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -1443,6 +1443,15 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
+ init.name = data->name;
+ init.flags = data->flags | CLK_IGNORE_UNUSED;
+ +
++ /*
++ * Some GPIO clocks for ethernet/wifi PLLs are marked as
++ * critical (since some platforms use them), but if the
++ * firmware didn't have them turned on then they clearly
++ * aren't actually critical.
++ */
++ if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0)
++ init.flags &= ~CLK_IS_CRITICAL;
++
+ /*
+ * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
+ * rate changes on at least of the parents.
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0024-sound-Demote-deferral-errors-to-INFO-level.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0024-sound-Demote-deferral-errors-to-INFO-level.patch
new file mode 100644
index 00000000..cd18e163
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0024-sound-Demote-deferral-errors-to-INFO-level.patch
@@ -0,0 +1,37 @@
+From c9dd599c2118333570669cce8359d8bf28dd61f8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 9 Feb 2017 14:36:44 +0000
+Subject: [PATCH 024/185] sound: Demote deferral errors to INFO level
++
+At present there is no mechanism to specify driver load order,
+which can lead to deferrals and repeated retries until successful.
+Since this situation is expected, reduce the dmesg level to
+INFO and mention that the operation will be retried.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ sound/soc/soc-core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 46e3ab0fced4..bba28797782e 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -901,7 +901,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
+ cpu_dai_component.dai_name = dai_link->cpu_dai_name;
+ rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component);
+ if (!rtd->cpu_dai) {
+- dev_info(card->dev, "ASoC: CPU DAI %s not registered\n",
++ dev_info(card->dev, "ASoC: CPU DAI %s not registered - will retry\n",
+ dai_link->cpu_dai_name);
+ goto _err_defer;
+ }
+@@ -914,7 +914,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
+ for_each_link_codecs(dai_link, i, codecs) {
+ codec_dais[i] = snd_soc_find_dai(codecs);
+ if (!codec_dais[i]) {
+- dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n",
++ dev_info(card->dev, "ASoC: CODEC DAI %s not registered - will retry\n",
+ codecs->dai_name);
+ goto _err_defer;
+ }
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0025-Update-vfpmodule.c.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0025-Update-vfpmodule.c.patch
new file mode 100644
index 00000000..15646c6e
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0025-Update-vfpmodule.c.patch
@@ -0,0 +1,139 @@
+From e2550fd2b923c34581fe379355bc831d09d66029 Mon Sep 17 00:00:00 2001
+From: Claggy3 <stephen.maclagan@hotmail.com>
+Date: Sat, 11 Feb 2017 14:00:30 +0000
+Subject: [PATCH 025/185] Update vfpmodule.c
+
+Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m.
+This patch fixes a problem with VFP state save and restore related
+to exception handling (panic with message "BUG: unsupported FP
+instruction in kernel mode") present on VFP11 floating point units
+(as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry
+Pi boards). This patch was developed and discussed on
+
+ https://github.com/raspberrypi/linux/issues/859
+
+A precondition to see the crashes is that floating point exception
+traps are enabled. In this case, the VFP11 might determine that a FPU
+operation needs to trap at a point in time when it is not possible to
+signal this to the ARM11 core any more. The VFP11 will then set the
+FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases,
+a second opcode might have been accepted by the VFP11 before the
+exception was detected and could be reported to the ARM11 - in this
+case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in
+FPINST2.)
+
+If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued
+by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode
+trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits
+to decide what actions to take, i.e., whether to emulate the opcodes
+found in FPINST and FPINST2, and whether to retry the bounced instruction.
+
+If a user space application has left the VFP11 in this "pending trap"
+state, the next FPU opcode issued to the VFP11 might actually be the
+VSTMIA operation vfp_save_state() uses to store the FPU registers
+to memory (in our test cases, when building the signal stack frame).
+In this case, the kernel crashes as described above.
+
+This patch fixes the problem by making sure that vfp_save_state() is
+always entered with FPEXC.EX cleared. (The current value of FPEXC has
+already been saved, so this does not corrupt the context. Clearing
+FPEXC.EX has no effects on FPINST or FPINST2. Also note that many
+callers already modify FPEXC by setting FPEXC.EN before invoking
+vfp_save_state().)
+
+This patch also addresses a second problem related to FPEXC.EX: After
+returning from signal handling, the kernel reloads the VFP context
+from the user mode stack. However, the current code explicitly clears
+both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these
+bits to be preserved, this patch disables clearing them for VFP
+implementations belonging to architecture 1. There should be no
+negative side effects: the user can set both bits by executing FPU
+opcodes anyway, and while user code may now place arbitrary values
+into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support
+code knows which instructions can be emulated, and rejects other
+opcodes with "unhandled bounce" messages, so there should be no
+security impact from allowing reloading FPEXC.EX and FPEXC.FP2V.
+
+Signed-off-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net>
+---
+ arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
+index ee7b07938dd5..ad4398dcca27 100644
+--- a/arch/arm/vfp/vfpmodule.c
++++ b/arch/arm/vfp/vfpmodule.c
+@@ -179,8 +179,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
+ * case the thread migrates to a different CPU. The
+ * restoring is done lazily.
+ */
+- if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu])
++ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
++ /* vfp_save_state oopses on VFP11 if EX bit set */
++ fmxr(FPEXC, fpexc & ~FPEXC_EX);
+ vfp_save_state(vfp_current_hw_state[cpu], fpexc);
++ }
+ #endif
+
+ /*
+@@ -457,13 +460,16 @@ static int vfp_pm_suspend(void)
+ /* if vfp is on, then save state for resumption */
+ if (fpexc & FPEXC_EN) {
+ pr_debug("%s: saving vfp state\n", __func__);
++ /* vfp_save_state oopses on VFP11 if EX bit set */
++ fmxr(FPEXC, fpexc & ~FPEXC_EX);
+ vfp_save_state(&ti->vfpstate, fpexc);
+
+ /* disable, just in case */
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+ } else if (vfp_current_hw_state[ti->cpu]) {
+ #ifndef CONFIG_SMP
+- fmxr(FPEXC, fpexc | FPEXC_EN);
++ /* vfp_save_state oopses on VFP11 if EX bit set */
++ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
+ vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
+ fmxr(FPEXC, fpexc);
+ #endif
+@@ -526,7 +532,8 @@ void vfp_sync_hwstate(struct thread_info *thread)
+ /*
+ * Save the last VFP state on this CPU.
+ */
+- fmxr(FPEXC, fpexc | FPEXC_EN);
++ /* vfp_save_state oopses on VFP11 if EX bit set */
++ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN);
+ vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN);
+ fmxr(FPEXC, fpexc);
+ }
+@@ -592,6 +599,7 @@ int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc)
+ struct thread_info *thread = current_thread_info();
+ struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
+ unsigned long fpexc;
++ u32 fpsid = fmrx(FPSID);
+
+ /* Disable VFP to avoid corrupting the new thread state. */
+ vfp_flush_hwstate(thread);
+@@ -614,8 +622,12 @@ int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc)
+ /* Ensure the VFP is enabled. */
+ fpexc |= FPEXC_EN;
+
+- /* Ensure FPINST2 is invalid and the exception flag is cleared. */
+- fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
++ /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */
++ if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) {
++ /* Ensure FPINST2 is invalid and the exception flag is cleared. */
++ fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
++ }
++
+ hwstate->fpexc = fpexc;
+
+ hwstate->fpinst = ufp_exc->fpinst;
+@@ -685,7 +697,8 @@ void kernel_neon_begin(void)
+ cpu = get_cpu();
+
+ fpexc = fmrx(FPEXC) | FPEXC_EN;
+- fmxr(FPEXC, fpexc);
++ /* vfp_save_state oopses on VFP11 if EX bit set */
++ fmxr(FPEXC, fpexc & ~FPEXC_EX);
+
+ /*
+ * Save the userland NEON/VFP state. Under UP,
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0026-i2c-bcm2835-Add-debug-support.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0026-i2c-bcm2835-Add-debug-support.patch
new file mode 100644
index 00000000..896dd092
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0026-i2c-bcm2835-Add-debug-support.patch
@@ -0,0 +1,191 @@
+From d81befb74af92d8e2b99af91e58573dadcb2e8f1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Tue, 1 Nov 2016 15:15:41 +0100
+Subject: [PATCH 026/185] i2c: bcm2835: Add debug support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This adds a debug module parameter to aid in debugging transfer issues
+by printing info to the kernel log. When enabled, status values are
+collected in the interrupt routine and msg info in
+bcm2835_i2c_start_transfer(). This is done in a way that tries to avoid
+affecting timing. Having printk in the isr can mask issues.
+
+debug values (additive):
+1: Print info on error
+2: Print info on all transfers
+3: Print messages before transfer is started
+
+The value can be changed at runtime:
+/sys/module/i2c_bcm2835/parameters/debug
+
+Example output, debug=3:
+[ 747.114448] bcm2835_i2c_xfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
+[ 747.114463] bcm2835_i2c_xfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
+[ 747.117809] start_transfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
+[ 747.117825] isr: remain=2, status=0x30000055 : TA TXW TXD TXE [i2c1]
+[ 747.117839] start_transfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
+[ 747.117849] isr: remain=32, status=0xd0000039 : TA RXR TXD RXD [i2c1]
+[ 747.117861] isr: remain=20, status=0xd0000039 : TA RXR TXD RXD [i2c1]
+[ 747.117870] isr: remain=8, status=0x32 : DONE TXD RXD [i2c1]
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+---
+ drivers/i2c/busses/i2c-bcm2835.c | 99 +++++++++++++++++++++++++++++++-
+ 1 file changed, 98 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
+index d2fbb4bb4a43..da8d409122c1 100644
+--- a/drivers/i2c/busses/i2c-bcm2835.c
++++ b/drivers/i2c/busses/i2c-bcm2835.c
+@@ -48,6 +48,18 @@
+ #define BCM2835_I2C_CDIV_MIN 0x0002
+ #define BCM2835_I2C_CDIV_MAX 0xFFFE
+
++static unsigned int debug;
++module_param(debug, uint, 0644);
++MODULE_PARM_DESC(debug, "1=err, 2=isr, 3=xfer");
++
++#define BCM2835_DEBUG_MAX 512
++struct bcm2835_debug {
++ struct i2c_msg *msg;
++ int msg_idx;
++ size_t remain;
++ u32 status;
++};
++
+ struct bcm2835_i2c_dev {
+ struct device *dev;
+ void __iomem *regs;
+@@ -61,8 +73,78 @@ struct bcm2835_i2c_dev {
+ u32 msg_err;
+ u8 *msg_buf;
+ size_t msg_buf_remaining;
++ struct bcm2835_debug debug[BCM2835_DEBUG_MAX];
++ unsigned int debug_num;
++ unsigned int debug_num_msgs;
+ };
+
++static inline void bcm2835_debug_add(struct bcm2835_i2c_dev *i2c_dev, u32 s)
++{
++ if (!i2c_dev->debug_num_msgs || i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
++ return;
++
++ i2c_dev->debug[i2c_dev->debug_num].msg = i2c_dev->curr_msg;
++ i2c_dev->debug[i2c_dev->debug_num].msg_idx =
++ i2c_dev->debug_num_msgs - i2c_dev->num_msgs;
++ i2c_dev->debug[i2c_dev->debug_num].remain = i2c_dev->msg_buf_remaining;
++ i2c_dev->debug[i2c_dev->debug_num].status = s;
++ i2c_dev->debug_num++;
++}
++
++static void bcm2835_debug_print_status(struct bcm2835_i2c_dev *i2c_dev,
++ struct bcm2835_debug *d)
++{
++ u32 s = d->status;
++
++ pr_info("isr: remain=%zu, status=0x%x : %s%s%s%s%s%s%s%s%s%s [i2c%d]\n",
++ d->remain, s,
++ s & BCM2835_I2C_S_TA ? "TA " : "",
++ s & BCM2835_I2C_S_DONE ? "DONE " : "",
++ s & BCM2835_I2C_S_TXW ? "TXW " : "",
++ s & BCM2835_I2C_S_RXR ? "RXR " : "",
++ s & BCM2835_I2C_S_TXD ? "TXD " : "",
++ s & BCM2835_I2C_S_RXD ? "RXD " : "",
++ s & BCM2835_I2C_S_TXE ? "TXE " : "",
++ s & BCM2835_I2C_S_RXF ? "RXF " : "",
++ s & BCM2835_I2C_S_ERR ? "ERR " : "",
++ s & BCM2835_I2C_S_CLKT ? "CLKT " : "",
++ i2c_dev->adapter.nr);
++}
++
++static void bcm2835_debug_print_msg(struct bcm2835_i2c_dev *i2c_dev,
++ struct i2c_msg *msg, int i, int total,
++ const char *fname)
++{
++ pr_info("%s: msg(%d/%d) %s addr=0x%02x, len=%u flags=%s%s%s%s%s%s%s [i2c%d]\n",
++ fname, i, total,
++ msg->flags & I2C_M_RD ? "read" : "write", msg->addr, msg->len,
++ msg->flags & I2C_M_TEN ? "TEN" : "",
++ msg->flags & I2C_M_RECV_LEN ? "RECV_LEN" : "",
++ msg->flags & I2C_M_NO_RD_ACK ? "NO_RD_ACK" : "",
++ msg->flags & I2C_M_IGNORE_NAK ? "IGNORE_NAK" : "",
++ msg->flags & I2C_M_REV_DIR_ADDR ? "REV_DIR_ADDR" : "",
++ msg->flags & I2C_M_NOSTART ? "NOSTART" : "",
++ msg->flags & I2C_M_STOP ? "STOP" : "",
++ i2c_dev->adapter.nr);
++}
++
++static void bcm2835_debug_print(struct bcm2835_i2c_dev *i2c_dev)
++{
++ struct bcm2835_debug *d;
++ unsigned int i;
++
++ for (i = 0; i < i2c_dev->debug_num; i++) {
++ d = &i2c_dev->debug[i];
++ if (d->status == ~0)
++ bcm2835_debug_print_msg(i2c_dev, d->msg, d->msg_idx,
++ i2c_dev->debug_num_msgs, "start_transfer");
++ else
++ bcm2835_debug_print_status(i2c_dev, d);
++ }
++ if (i2c_dev->debug_num >= BCM2835_DEBUG_MAX)
++ pr_info("BCM2835_DEBUG_MAX reached\n");
++}
++
+ static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev,
+ u32 reg, u32 val)
+ {
+@@ -181,6 +263,7 @@ static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev)
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr);
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len);
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c);
++ bcm2835_debug_add(i2c_dev, ~0);
+ }
+
+ static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev)
+@@ -207,6 +290,7 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
+ u32 val, err;
+
+ val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
++ bcm2835_debug_add(i2c_dev, val);
+
+ err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
+ if (err) {
+@@ -273,6 +357,13 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ unsigned long time_left;
+ int i, ret;
+
++ if (debug)
++ i2c_dev->debug_num_msgs = num;
++
++ if (debug > 2)
++ for (i = 0; i < num; i++)
++ bcm2835_debug_print_msg(i2c_dev, &msgs[i], i + 1, num, __func__);
++
+ for (i = 0; i < (num - 1); i++)
+ if (msgs[i].flags & I2C_M_RD) {
+ dev_warn_once(i2c_dev->dev,
+@@ -295,6 +386,10 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+
+ bcm2835_i2c_finish_transfer(i2c_dev);
+
++ if (debug > 1 || (debug && (!time_left || i2c_dev->msg_err)))
++ bcm2835_debug_print(i2c_dev);
++ i2c_dev->debug_num_msgs = 0;
++ i2c_dev->debug_num = 0;
+ if (!time_left) {
+ bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
+ BCM2835_I2C_C_CLEAR);
+@@ -305,7 +400,9 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+ if (!i2c_dev->msg_err)
+ return num;
+
+- dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
++ if (debug)
++ dev_err(i2c_dev->dev, "i2c transfer failed: %x\n",
++ i2c_dev->msg_err);
+
+ if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
+ return -EREMOTEIO;
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0027-mm-Remove-the-PFN-busy-warning.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0027-mm-Remove-the-PFN-busy-warning.patch
new file mode 100644
index 00000000..3655c1ad
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0027-mm-Remove-the-PFN-busy-warning.patch
@@ -0,0 +1,27 @@
+From d82373294acade79b2fa3c3fff8d883c630aca8c Mon Sep 17 00:00:00 2001
+From: Eric Anholt <eric@anholt.net>
+Date: Thu, 18 Dec 2014 16:07:15 -0800
+Subject: [PATCH 027/185] mm: Remove the PFN busy warning
+
+See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is
+expected sometimes when using CMA. However, that commit still spams
+my kernel log with these warnings.
+
+Signed-off-by: Eric Anholt <eric@anholt.net>
+---
+ mm/page_alloc.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index c02cff1ed56e..99fb903e4b5a 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -8312,8 +8312,6 @@ int alloc_contig_range(unsigned long start, unsigned long end,
+
+ /* Make sure the range is really isolated. */
+ if (test_pages_isolated(outer_start, end, false)) {
+- pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
+- __func__, outer_start, end);
+ ret = -EBUSY;
+ goto done;
+ }
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0028-ASoC-Add-prompt-for-ICS43432-codec.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0028-ASoC-Add-prompt-for-ICS43432-codec.patch
new file mode 100644
index 00000000..66563569
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0028-ASoC-Add-prompt-for-ICS43432-codec.patch
@@ -0,0 +1,27 @@
+From 31136b29dfd9a206d2466aa13c977a39030454ad Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 23 Mar 2017 10:06:56 +0000
+Subject: [PATCH 028/185] ASoC: Add prompt for ICS43432 codec
+
+Without a prompt string, a config setting can't be included in a
+defconfig. Give CONFIG_SND_SOC_ICS43432 a prompt so that Pi soundcards
+can use the driver.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ sound/soc/codecs/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 667fc1d59e18..a7834032afba 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -676,7 +676,7 @@ config SND_SOC_HDAC_HDA
+ select SND_HDA
+
+ config SND_SOC_ICS43432
+- tristate
++ tristate "InvenSense ICS43432 I2S microphone codec"
+
+ config SND_SOC_INNO_RK3036
+ tristate "Inno codec driver for RK3036 SoC"
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0029-irqchip-irq-bcm2836-Remove-regmap-and-syscon-use.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0029-irqchip-irq-bcm2836-Remove-regmap-and-syscon-use.patch
new file mode 100644
index 00000000..d9d95c19
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0029-irqchip-irq-bcm2836-Remove-regmap-and-syscon-use.patch
@@ -0,0 +1,116 @@
+From 61877a9c52de96edd3a15bb715e4d11cdcf4414b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 23 Jan 2018 16:52:45 +0000
+Subject: [PATCH 029/185] irqchip: irq-bcm2836: Remove regmap and syscon use
+
+The syscon node defines a register range that duplicates that used by
+the local_intc node on bcm2836/7. Since irq-bcm2835 and irq-bcm2836 are
+built in and always present together (both drivers are enabled by
+CONFIG_ARCH_BCM2835), it is possible to replace the syscon usage with a
+global variable that simplifies the code. Doing so does lose the
+locking provided by regmap, but as only one side is using the regmap
+interface (irq-bcm2835 uses readl and write) there is no loss of
+atomicity.
+
+See: https://github.com/raspberrypi/firmware/issues/926
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/irqchip/irq-bcm2835.c | 32 ++++++++++++--------------------
+ drivers/irqchip/irq-bcm2836.c | 5 +++++
+ 2 files changed, 17 insertions(+), 20 deletions(-)
+
+diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
+index 2fccc5cfe9f3..88abd2e67866 100644
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -41,8 +41,6 @@
+ #include <linux/of_irq.h>
+ #include <linux/irqchip.h>
+ #include <linux/irqdomain.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/regmap.h>
+
+ #include <asm/exception.h>
+ #include <asm/mach/irq.h>
+@@ -91,7 +89,7 @@ struct armctrl_ic {
+ void __iomem *enable[NR_BANKS];
+ void __iomem *disable[NR_BANKS];
+ struct irq_domain *domain;
+- struct regmap *local_regmap;
++ void __iomem *local_base;
+ };
+
+ static struct armctrl_ic intc __read_mostly;
+@@ -128,24 +126,20 @@ static void armctrl_unmask_irq(struct irq_data *d)
+ if (d->hwirq >= NUMBER_IRQS) {
+ if (num_online_cpus() > 1) {
+ unsigned int data;
+- int ret;
+
+- if (!intc.local_regmap) {
+- pr_err("FIQ is disabled due to missing regmap\n");
++ if (!intc.local_base) {
++ pr_err("FIQ is disabled due to missing arm_local_intc\n");
+ return;
+ }
+
+- ret = regmap_read(intc.local_regmap,
+- ARM_LOCAL_GPU_INT_ROUTING, &data);
+- if (ret) {
+- pr_err("Failed to read int routing %d\n", ret);
+- return;
+- }
++ data = readl_relaxed(intc.local_base +
++ ARM_LOCAL_GPU_INT_ROUTING);
+
+ data &= ~0xc;
+ data |= (1 << 2);
+- regmap_write(intc.local_regmap,
+- ARM_LOCAL_GPU_INT_ROUTING, data);
++ writel_relaxed(data,
++ intc.local_base +
++ ARM_LOCAL_GPU_INT_ROUTING);
+ }
+
+ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
+@@ -231,12 +225,10 @@ static int __init armctrl_of_init(struct device_node *node,
+ }
+
+ if (is_2836) {
+- intc.local_regmap =
+- syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
+- if (IS_ERR(intc.local_regmap)) {
+- pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
+- intc.local_regmap = NULL;
+- }
++ extern void __iomem * __attribute__((weak)) arm_local_intc;
++ intc.local_base = arm_local_intc;
++ if (!intc.local_base)
++ pr_err("Failed to get local intc base. FIQ is disabled for cpus > 1\n");
+ }
+
+ /* Make a duplicate irq range which is used to enable FIQ */
+diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
+index c006a8ac10d5..49642bcd0b75 100644
+--- a/drivers/irqchip/irq-bcm2836.c
++++ b/drivers/irqchip/irq-bcm2836.c
+@@ -21,6 +21,9 @@ struct bcm2836_arm_irqchip_intc {
+
+ static struct bcm2836_arm_irqchip_intc intc __read_mostly;
+
++void __iomem *arm_local_intc;
++EXPORT_SYMBOL_GPL(arm_local_intc);
++
+ static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset,
+ unsigned int bit,
+ int cpu)
+@@ -225,6 +228,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
+ panic("%pOF: unable to map local interrupt registers\n", node);
+ }
+
++ arm_local_intc = intc.base;
++
+ bcm2835_init_local_timer_frequency();
+
+ intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0030-lan78xx-Enable-LEDs-and-auto-negotiation.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0030-lan78xx-Enable-LEDs-and-auto-negotiation.patch
new file mode 100644
index 00000000..52ddb661
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0030-lan78xx-Enable-LEDs-and-auto-negotiation.patch
@@ -0,0 +1,50 @@
+From 5947d9f6cf0668cbd16b032b23b389847a22d998 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 17 Oct 2017 15:04:29 +0100
+Subject: [PATCH 030/185] lan78xx: Enable LEDs and auto-negotiation
+
+For applications of the LAN78xx that don't have valid programmed
+EEPROMs or OTPs, enabling both LEDs and auto-negotiation by default
+seems reasonable.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/net/usb/lan78xx.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
+index 3d92ea6fcc02..d533bf2400ee 100644
+--- a/drivers/net/usb/lan78xx.c
++++ b/drivers/net/usb/lan78xx.c
+@@ -2461,6 +2461,11 @@ static int lan78xx_reset(struct lan78xx_net *dev)
+ int ret = 0;
+ unsigned long timeout;
+ u8 sig;
++ bool has_eeprom;
++ bool has_otp;
++
++ has_eeprom = !lan78xx_read_eeprom(dev, 0, 0, NULL);
++ has_otp = !lan78xx_read_otp(dev, 0, 0, NULL);
+
+ ret = lan78xx_read_reg(dev, HW_CFG, &buf);
+ buf |= HW_CFG_LRST_;
+@@ -2514,6 +2519,9 @@ static int lan78xx_reset(struct lan78xx_net *dev)
+
+ ret = lan78xx_read_reg(dev, HW_CFG, &buf);
+ buf |= HW_CFG_MEF_;
++ /* If no valid EEPROM and no valid OTP, enable the LEDs by default */
++ if (!has_eeprom && !has_otp)
++ buf |= HW_CFG_LED0_EN_ | HW_CFG_LED1_EN_;
+ ret = lan78xx_write_reg(dev, HW_CFG, buf);
+
+ ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
+@@ -2569,6 +2577,9 @@ static int lan78xx_reset(struct lan78xx_net *dev)
+ buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
+ }
+ }
++ /* If no valid EEPROM and no valid OTP, enable AUTO negotiation */
++ if (!has_eeprom && !has_otp)
++ buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
+ ret = lan78xx_write_reg(dev, MAC_CR, buf);
+
+ ret = lan78xx_read_reg(dev, MAC_TX, &buf);
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0031-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0031-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch
new file mode 100644
index 00000000..df38ecaf
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0031-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch
@@ -0,0 +1,31 @@
+From 50490bd6925a8634ccd26d700c3b0973ca47a01a Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 23 Feb 2016 17:26:48 +0000
+Subject: [PATCH 031/185] amba_pl011: Don't use DT aliases for numbering
+
+The pl011 driver looks for DT aliases of the form "serial<n>",
+and if found uses <n> as the device ID. This can cause
+/dev/ttyAMA0 to become /dev/ttyAMA1, which is confusing if the
+other serial port is provided by the 8250 driver which doesn't
+use the same logic.
+---
+ drivers/tty/serial/amba-pl011.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
+index 89ade213a1a9..18225dda654b 100644
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -2578,7 +2578,12 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
++ /* Don't use DT serial<n> aliases - it causes the device to
++ be renumbered to ttyAMA1 if it is the second serial port in the
++ system, even though the other one is ttyS0. The 8250 driver
++ doesn't use this logic, so always remains ttyS0.
+ index = pl011_probe_dt_alias(index, dev);
++ */
+
+ uap->old_cr = 0;
+ uap->port.dev = dev;
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0032-amba_pl011-Round-input-clock-up.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0032-amba_pl011-Round-input-clock-up.patch
new file mode 100644
index 00000000..4d16748b
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0032-amba_pl011-Round-input-clock-up.patch
@@ -0,0 +1,88 @@
+From 0191b53d72b5cd9006280e4a6659ba138ea67eb4 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 1 Mar 2017 16:07:39 +0000
+Subject: [PATCH 032/185] amba_pl011: Round input clock up
+
+The UART clock is initialised to be as close to the requested
+frequency as possible without exceeding it. Now that there is a
+clock manager that returns the actual frequencies, an expected
+48MHz clock is reported as 47999625. If the requested baudrate
+== requested clock/16, there is no headroom and the slight
+reduction in actual clock rate results in failure.
+
+Detect cases where it looks like a "round" clock was chosen and
+adjust the reported clock to match that "round" value. As the
+code comment says:
+
+/*
+ * If increasing a clock by less than 0.1% changes it
+ * from ..999.. to ..000.., round up.
+ */
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/tty/serial/amba-pl011.c | 23 +++++++++++++++++++++--
+ 1 file changed, 21 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
+index 18225dda654b..02275f96dbca 100644
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1652,6 +1652,23 @@ static void pl011_put_poll_char(struct uart_port *port,
+
+ #endif /* CONFIG_CONSOLE_POLL */
+
++unsigned long pl011_clk_round(unsigned long clk)
++{
++ unsigned long scaler;
++
++ /*
++ * If increasing a clock by less than 0.1% changes it
++ * from ..999.. to ..000.., round up.
++ */
++ scaler = 1;
++ while (scaler * 100000 < clk)
++ scaler *= 10;
++ if ((clk + scaler - 1)/scaler % 1000 == 0)
++ clk = (clk/scaler + 1) * scaler;
++
++ return clk;
++}
++
+ static int pl011_hwinit(struct uart_port *port)
+ {
+ struct uart_amba_port *uap =
+@@ -1668,7 +1685,7 @@ static int pl011_hwinit(struct uart_port *port)
+ if (retval)
+ return retval;
+
+- uap->port.uartclk = clk_get_rate(uap->clk);
++ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk));
+
+ /* Clear pending error and receive interrupts */
+ pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS |
+@@ -2324,7 +2341,7 @@ static int __init pl011_console_setup(struct console *co, char *options)
+ plat->init();
+ }
+
+- uap->port.uartclk = clk_get_rate(uap->clk);
++ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk));
+
+ if (uap->vendor->fixed_options) {
+ baud = uap->fixed_baud;
+@@ -2509,6 +2526,7 @@ static struct uart_driver amba_reg = {
+ .cons = AMBA_CONSOLE,
+ };
+
++#if 0
+ static int pl011_probe_dt_alias(int index, struct device *dev)
+ {
+ struct device_node *np;
+@@ -2540,6 +2558,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
+
+ return ret;
+ }
++#endif
+
+ /* unregisters the driver also if no more ports are left */
+ static void pl011_unregister_port(struct uart_amba_port *uap)
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0033-amba_pl011-Insert-mb-for-correct-FIFO-handling.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0033-amba_pl011-Insert-mb-for-correct-FIFO-handling.patch
new file mode 100644
index 00000000..f497d904
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0033-amba_pl011-Insert-mb-for-correct-FIFO-handling.patch
@@ -0,0 +1,29 @@
+From 195f81da0a0c4d88b3ab4c8b67890a88b08926a2 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 29 Sep 2017 10:32:19 +0100
+Subject: [PATCH 033/185] amba_pl011: Insert mb() for correct FIFO handling
+
+The pl011 register accessor functions use the _relaxed versions of the
+standard readl() and writel() functions, meaning that there are no
+automatic memory barriers. When polling a FIFO status register to check
+for fullness, it is necessary to ensure that any outstanding writes have
+completed; otherwise the flags are effectively stale, making it possible
+that the next write is to a full FIFO.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/tty/serial/amba-pl011.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
+index 02275f96dbca..39d717e94af3 100644
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1385,6 +1385,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
+ return false; /* unable to transmit character */
+
+ pl011_write(c, uap, REG_DR);
++ mb();
+ uap->port.icount.tx++;
+
+ return true;
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0034-amba_pl011-Add-cts-event-workaround-DT-property.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0034-amba_pl011-Add-cts-event-workaround-DT-property.patch
new file mode 100644
index 00000000..3117df37
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0034-amba_pl011-Add-cts-event-workaround-DT-property.patch
@@ -0,0 +1,54 @@
+From 2e6001c297a892206226e25d72ed864b4e7740b8 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 29 Sep 2017 10:32:19 +0100
+Subject: [PATCH 034/185] amba_pl011: Add cts-event-workaround DT property
+
+The BCM2835 PL011 implementation seems to have a bug that can lead to a
+transmission lockup if CTS changes frequently. A workaround was added to
+the driver with a vendor-specific flag to enable it, but this flag is
+currently not set for ARM implementations.
+
+Add a "cts-event-workaround" property to Pi DTBs and use the presence
+of that property to force the flag to be enabled in the driver.
+
+See: https://github.com/raspberrypi/linux/issues/1280
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ Documentation/devicetree/bindings/serial/pl011.yaml | 6 ++++++
+ drivers/tty/serial/amba-pl011.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/serial/pl011.yaml b/Documentation/devicetree/bindings/serial/pl011.yaml
+index 1a64d59152aa..a4650389eded 100644
+--- a/Documentation/devicetree/bindings/serial/pl011.yaml
++++ b/Documentation/devicetree/bindings/serial/pl011.yaml
+@@ -100,6 +100,12 @@ properties:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - default: 3000
+
++ cts-event-workaround:
++ description:
++ Enables the (otherwise vendor-specific) workaround for the
++ CTS-induced TX lockup.
++ type: boolean
++
+ required:
+ - compatible
+ - reg
+diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
+index 39d717e94af3..6f15f32fa194 100644
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -2661,6 +2661,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
+ if (IS_ERR(uap->clk))
+ return PTR_ERR(uap->clk);
+
++ if (of_property_read_bool(dev->dev.of_node, "cts-event-workaround")) {
++ vendor->cts_event_workaround = true;
++ dev_info(&dev->dev, "cts_event_workaround enabled\n");
++ }
++
+ uap->reg_offset = vendor->reg_offset;
+ uap->vendor = vendor;
+ uap->fifosize = vendor->get_fifosize(dev);
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0035-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0035-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch
new file mode 100644
index 00000000..bf31b3d6
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0035-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch
@@ -0,0 +1,24 @@
+From 2b3dcd43338e2e79381470115a94619c44574d18 Mon Sep 17 00:00:00 2001
+From: notro <notro@tronnes.org>
+Date: Thu, 10 Jul 2014 13:59:47 +0200
+Subject: [PATCH 035/185] pinctrl-bcm2835: Set base to 0 give expected gpio
+ numbering
+
+Signed-off-by: Noralf Tronnes <notro@tronnes.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+index 183d1ffe6a75..cb718971829d 100644
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -342,7 +342,7 @@ static const struct gpio_chip bcm2835_gpio_chip = {
+ .get = bcm2835_gpio_get,
+ .set = bcm2835_gpio_set,
+ .set_config = gpiochip_generic_config,
+- .base = -1,
++ .base = 0,
+ .ngpio = BCM2835_NUM_GPIOS,
+ .can_sleep = false,
+ };
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0036-Main-bcm2708-bcm2709-linux-port.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0036-Main-bcm2708-bcm2709-linux-port.patch
new file mode 100644
index 00000000..b98da3b6
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0036-Main-bcm2708-bcm2709-linux-port.patch
@@ -0,0 +1,158 @@
+From 5d5d8dcfe41978b13cdbbb810ef768838acd4481 Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Sun, 12 May 2013 12:24:19 +0100
+Subject: [PATCH 036/185] Main bcm2708/bcm2709 linux port
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm2709: Drop platform smp and timer init code
+
+irq-bcm2836 handles this through these functions:
+bcm2835_init_local_timer_frequency()
+bcm2836_arm_irqchip_smp_init()
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+bcm270x: Use watchdog for reboot/poweroff
+
+The watchdog driver already has support for reboot/poweroff.
+Make use of this and remove the code from the platform files.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+board_bcm2835: Remove coherent dma pool increase - API has gone
+---
+ arch/arm/mach-bcm/Kconfig | 1 +
+ arch/arm/mm/proc-v6.S | 15 ++++++++++++---
+ drivers/irqchip/irq-bcm2835.c | 7 ++++++-
+ drivers/mailbox/bcm2835-mailbox.c | 18 ++++++++++++++++--
+ 4 files changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
+index c464f2258c3f..b975b97deca9 100644
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -169,6 +169,7 @@ config ARCH_BCM2835
+ select PINCTRL
+ select PINCTRL_BCM2835
+ select MFD_CORE
++ select MFD_SYSCON if ARCH_MULTI_V7
+ help
+ This enables support for the Broadcom BCM2835 and BCM2836 SoCs.
+ This SoC is used in the Raspberry Pi and Roku 2 devices.
+diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
+index 06d890a2342b..30d96e81c0e0 100644
+--- a/arch/arm/mm/proc-v6.S
++++ b/arch/arm/mm/proc-v6.S
+@@ -73,10 +73,19 @@ ENDPROC(cpu_v6_reset)
+ *
+ * IRQs are already disabled.
+ */
++
++/* See jira SW-5991 for details of this workaround */
+ ENTRY(cpu_v6_do_idle)
+- mov r1, #0
+- mcr p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
+- mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt
++ .align 5
++ mov r1, #2
++1: subs r1, #1
++ nop
++ mcreq p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode
++ mcreq p15, 0, r1, c7, c0, 4 @ wait for interrupt
++ nop
++ nop
++ nop
++ bne 1b
+ ret lr
+
+ ENTRY(cpu_v6_dcache_clean_area)
+diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
+index 88abd2e67866..ff7b998579c1 100644
+--- a/drivers/irqchip/irq-bcm2835.c
++++ b/drivers/irqchip/irq-bcm2835.c
+@@ -43,7 +43,9 @@
+ #include <linux/irqdomain.h>
+
+ #include <asm/exception.h>
++#ifndef CONFIG_ARM64
+ #include <asm/mach/irq.h>
++#endif
+
+ /* Put the bank and irq (32 bits) into the hwirq */
+ #define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
+@@ -71,6 +73,7 @@
+ #define NR_BANKS 3
+ #define IRQS_PER_BANK 32
+ #define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
++#undef FIQ_START
+ #define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
+
+ static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
+@@ -238,10 +241,12 @@ static int __init armctrl_of_init(struct device_node *node,
+ MAKE_HWIRQ(b, i) + NUMBER_IRQS);
+ BUG_ON(irq <= 0);
+ irq_set_chip(irq, &armctrl_chip);
+- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++ irq_set_probe(irq);
+ }
+ }
++#ifndef CONFIG_ARM64
+ init_FIQ(FIQ_START);
++#endif
+
+ return 0;
+ }
+diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c
+index 39761d190545..9766d8b50778 100644
+--- a/drivers/mailbox/bcm2835-mailbox.c
++++ b/drivers/mailbox/bcm2835-mailbox.c
+@@ -45,12 +45,15 @@
+ #define MAIL1_WRT (ARM_0_MAIL1 + 0x00)
+ #define MAIL1_STA (ARM_0_MAIL1 + 0x18)
+
++/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
++#ifndef ARM_MS_FULL
+ /* Status register: FIFO state. */
+ #define ARM_MS_FULL BIT(31)
+ #define ARM_MS_EMPTY BIT(30)
+
+ /* Configuration register: Enable interrupts. */
+ #define ARM_MC_IHAVEDATAIRQEN BIT(0)
++#endif
+
+ struct bcm2835_mbox {
+ void __iomem *regs;
+@@ -145,7 +148,7 @@ static int bcm2835_mbox_probe(struct platform_device *pdev)
+ return -ENOMEM;
+ spin_lock_init(&mbox->lock);
+
+- ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
+ bcm2835_mbox_irq, 0, dev_name(dev), mbox);
+ if (ret) {
+ dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
+@@ -195,7 +198,18 @@ static struct platform_driver bcm2835_mbox_driver = {
+ },
+ .probe = bcm2835_mbox_probe,
+ };
+-module_platform_driver(bcm2835_mbox_driver);
++
++static int __init bcm2835_mbox_init(void)
++{
++ return platform_driver_register(&bcm2835_mbox_driver);
++}
++arch_initcall(bcm2835_mbox_init);
++
++static void __init bcm2835_mbox_exit(void)
++{
++ platform_driver_unregister(&bcm2835_mbox_driver);
++}
++module_exit(bcm2835_mbox_exit);
+
+ MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
+ MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");
diff --git a/sys-kernel/boest-v5.1.1/raspberrypi/0037-Add-dwc_otg-driver.patch b/sys-kernel/boest-v5.1.1/raspberrypi/0037-Add-dwc_otg-driver.patch
new file mode 100644
index 00000000..fd749714
--- /dev/null
+++ b/sys-kernel/boest-v5.1.1/raspberrypi/0037-Add-dwc_otg-driver.patch
@@ -0,0 +1,61396 @@
+From 15a65afb365f4d0510736e37a591541a775d00ad Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Wed, 1 May 2013 19:46:17 +0100
+Subject: [PATCH 037/185] Add dwc_otg driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
++
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+usb: dwc: fix lockdep false positive
+
+Signed-off-by: Kari Suvanto <karis79@gmail.com>
++
+usb: dwc: fix inconsistent lock state
++
+Signed-off-by: Kari Suvanto <karis79@gmail.com>
++
+Add FIQ patch to dwc_otg driver. Enable with dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance.
+Thanks to Gordon and Costas
++
+Avoid dynamic memory allocation for channel lock in USB driver. Thanks ddv2005.
++
+Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh
++
+Make sure we wait for the reset to finish
+
+dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel
+ memory corruption, escalating to OOPS under high USB load.
++
+dwc_otg: Fix unsafe access of QTD during URB enqueue
+
+In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the
+transaction could complete almost immediately after the qtd was assigned
+to a host channel during URB enqueue, which meant the qtd pointer was no
+longer valid having been completed and removed. Usually, this resulted in
+an OOPS during URB submission. By predetermining whether transactions
+need to be queued or not, this unsafe pointer access is avoided.
++
+This bug was only evident on the Pi model A where a device was attached
+that had no periodic endpoints (e.g. USB pendrive or some wlan devices).
++
+dwc_otg: Fix incorrect URB allocation error handling
+
+If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS
+because for some reason a member of the *unallocated* struct was set to
+zero. Error handling changed to fail correctly.
++
+dwc_otg: fix potential use-after-free case in interrupt handler
++
+If a transaction had previously aborted, certain interrupts are
+enabled to track error counts and reset where necessary. On IN
+endpoints the host generates an ACK interrupt near-simultaneously
+with completion of transfer. In the case where this transfer had
+previously had an error, this results in a use-after-free on
+the QTD memory space with a 1-byte length being overwritten to
+0x00.
++
+dwc_otg: add handling of SPLIT transaction data toggle errors
+
+Previously a data toggle error on packets from a USB1.1 device behind
+a TT would result in the Pi locking up as the driver never handled
+the associated interrupt. Patch adds basic retry mechanism and
+interrupt acknowledgement to cater for either a chance toggle error or
+for devices that have a broken initial toggle state (FT8U232/FT232BM).
+
+dwc_otg: implement tasklet for returning URBs to usbcore hcd layer
++
+The dwc_otg driver interrupt handler for transfer completion will spend
+a very long time with interrupts disabled when a URB is completed -
+this is because usb_hcd_giveback_urb is called from within the handler
+which for a USB device driver with complicated processing (e.g. webcam)
+will take an exorbitant amount of time to complete. This results in
+missed completion interrupts for other USB packets which lead to them
+being dropped due to microframe overruns.
++
+This patch splits returning the URB to the usb hcd layer into a
+high-priority tasklet. This will have most benefit for isochronous IN
+transfers but will also have incidental benefit where multiple periodic
+devices are active at once.
++
+dwc_otg: fix NAK holdoff and allow on split transactions only
++
+This corrects a bug where if a single active non-periodic endpoint
+had at least one transaction in its qh, on frnum == MAX_FRNUM the qh
+would get skipped and never get queued again. This would result in
+a silent device until error detection (automatic or otherwise) would
+either reset the device or flush and requeue the URBs.
++
+Additionally the NAK holdoff was enabled for all transactions - this
+would potentially stall a HS endpoint for 1ms if a previous error state
+enabled this interrupt and the next response was a NAK. Fix so that
+only split transactions get held off.
++
+dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held in completion handler
++
+usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it
+asynchronously in the tasklet was not safe (regression in
+c4564d4a1a0a9b10d4419e48239f5d99e88d2667).
++
+This change unlinks it from the endpoint prior to queueing it for handling in
+the tasklet, and also adds a check to ensure the urb is OK to be unlinked
+before doing so.
++
+NULL pointer dereference kernel oopses had been observed in usb_hcd_giveback_urb
+when a USB device was unplugged/replugged during data transfer. This effect
+was reproduced using automated USB port power control, hundreds of replug
+events were performed during active transfers to confirm that the problem was
+eliminated.
++
+USB fix using a FIQ to implement split transactions
++
+This commit adds a FIQ implementaion that schedules
+the split transactions using a FIQ so we don't get
+held off by the interrupt latency of Linux
++
+dwc_otg: fix device attributes and avoid kernel warnings on boot
+
+dcw_otg: avoid logging function that can cause panics
+
+See: https://github.com/raspberrypi/firmware/issues/21
+Thanks to cleverca22 for fix
+
+dwc_otg: mask correct interrupts after transaction error recovery
+
+The dwc_otg driver will unmask certain interrupts on a transaction
+that previously halted in the error state in order to reset the
+QTD error count. The various fine-grained interrupt handlers do not
+consider that other interrupts besides themselves were unmasked.
+
+By disabling the two other interrupts only ever enabled in DMA mode
+for this purpose, we can avoid unnecessary function calls in the
+IRQ handler. This will also prevent an unneccesary FIQ interrupt
+from being generated if the FIQ is enabled.
+
+dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ
+
+In the case of a transaction to a device that had previously aborted
+due to an error, several interrupts are enabled to reset the error
+count when a device responds. This has the side-effect of making the
+FIQ thrash because the hardware will generate multiple instances of
+a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK
+on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the
+associated interrupts.
+
+Additionally, on non-split transactions make sure that only unmasked
+interrupts are cleared. This caused a hard-to-trigger but serious
+race condition when you had the combination of an endpoint awaiting
+error recovery and a transaction completed on an endpoint - due to
+the sequencing and timing of interrupts generated by the dwc_otg core,
+it was possible to confuse the IRQ handler.
+
+Fix function tracing
+
+dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue
+
+dwc_otg: prevent OOPSes during device disconnects
+
+The dwc_otg_urb_enqueue function is thread-unsafe. In particular the
+access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and
+friends does not occur within a critical section and so if a device
+was unplugged during activity there was a high chance that the
+usbcore hub_thread would try to disable the endpoint with partially-
+formed entries in the URB queue. This would result in BUG() or null
+pointer dereferences.
+
+Fix so that access of urb->hcpriv, enqueuing to the hardware and
+adding to usbcore endpoint URB lists is contained within a single
+critical section.
+
+dwc_otg: prevent BUG() in TT allocation if hub address is > 16
+
+A fixed-size array is used to track TT allocation. This was
+previously set to 16 which caused a crash because
+dwc_otg_hcd_allocate_port would read past the end of the array.
+
+This was hit if a hub was plugged in which enumerated as addr > 16,
+due to previous device resets or unplugs.
+
+Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows
+to a large size if 128 hub addresses are supported. This field is
+for debug only for tracking which frame an allocate happened in.
+
+dwc_otg: make channel halts with unknown state less damaging
+
+If the IRQ received a channel halt interrupt through the FIQ
+with no other bits set, the IRQ would not release the host
+channel and never complete the URB.
+
+Add catchall handling to treat as a transaction error and retry.
+
+dwc_otg: fiq_split: use TTs with more granularity
+
+This fixes certain issues with split transaction scheduling.
+
+- Isochronous multi-packet OUT transactions now hog the TT until
+ they are completed - this prevents hubs aborting transactions
+ if they get a periodic start-split out-of-order
+- Don't perform TT allocation on non-periodic endpoints - this
+ allows simultaneous use of the TT's bulk/control and periodic
+ transaction buffers
+
+This commit will mainly affect USB audio playback.
+
+dwc_otg: fix potential sleep while atomic during urb enqueue
+
+Fixes a regression introduced with eb1b482a. Kmalloc called from
+dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have
+the GPF_ATOMIC flag set. Force this flag when inside the larger
+critical section.
+
+dwc_otg: make fiq_split_enable imply fiq_fix_enable
+
+Failing to set up the FIQ correctly would result in
+"IRQ 32: nobody cared" errors in dmesg.
+
+dwc_otg: prevent crashes on host port disconnects
+
+Fix several issues resulting in crashes or inconsistent state
+if a Model A root port was disconnected.
+
+- Clean up queue heads properly in kill_urbs_in_qh_list by
+ removing the empty QHs from the schedule lists
+- Set the halt status properly to prevent IRQ handlers from
+ using freed memory
+- Add fiq_split related cleanup for saved registers
+- Make microframe scheduling reclaim host channels if
+ active during a disconnect
+- Abort URBs with -ESHUTDOWN status response, informing
+ device drivers so they respond in a more correct fashion
+ and don't try to resubmit URBs
+- Prevent IRQ handlers from attempting to handle channel
+ interrupts if the associated URB was dequeued (and the
+ driver state was cleared)
+
+dwc_otg: prevent leaking URBs during enqueue
+
+A dwc_otg_urb would get leaked if the HCD enqueue function
+failed for any reason. Free the URB at the appropriate points.
+
+dwc_otg: Enable NAK holdoff for control split transactions
+
+Certain low-speed devices take a very long time to complete a
+data or status stage of a control transaction, producing NAK
+responses until they complete internal processing - the USB2.0
+spec limit is up to 500mS. This causes the same type of interrupt
+storm as seen with USB-serial dongles prior to c8edb238.
+
+In certain circumstances, usually while booting, this interrupt
+storm could cause SD card timeouts.
+
+dwc_otg: Fix for occasional lockup on boot when doing a USB reset
+
+dwc_otg: Don't issue traffic to LS devices in FS mode
+
+Issuing low-speed packets when the root port is in full-speed mode
+causes the root port to stop responding. Explicitly fail when
+enqueuing URBs to a LS endpoint on a FS bus.
+
+Fix ARM architecture issue with local_irq_restore()
+
+If local_fiq_enable() is called before a local_irq_restore(flags) where
+the flags variable has the F bit set, the FIQ will be erroneously disabled.
+
+Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR.
+
+Also fix some of the hacks previously implemented for previous dwc_otg
+incarnations.
+
+dwc_otg: fiq_fsm: Base commit for driver rewrite
+
+This commit removes the previous FIQ fixes entirely and adds fiq_fsm.
+
+This rewrite features much more complete support for split transactions
+and takes into account several OTG hardware bugs. High-speed
+isochronous transactions are also capable of being performed by fiq_fsm.
+
+All driver options have been removed and replaced with:
+ - dwc_otg.fiq_enable (bool)
+ - dwc_otg.fiq_fsm_enable (bool)
+ - dwc_otg.fiq_fsm_mask (bitmask)
+ - dwc_otg.nak_holdoff (unsigned int)
+
+Defaults are specified such that fiq_fsm behaves similarly to the
+previously implemented FIQ fixes.
+
+fiq_fsm: Push error recovery into the FIQ when fiq_fsm is used
+
+If the transfer associated with a QTD failed due to a bus error, the HCD
+would retry the transfer up to 3 times (implementing the USB2.0
+three-strikes retry in software).
+
+Due to the masking mechanism used by fiq_fsm, it is only possible to pass
+a single interrupt through to the HCD per-transfer.
+
+In this instance host channels would fall off the radar because the error
+reset would function, but the subsequent channel halt would be lost.
+
+Push the error count reset into the FIQ handler.
+
+fiq_fsm: Implement timeout mechanism
+
+For full-speed endpoints with a large packet size, interrupt latency
+runs the risk of the FIQ starting a transaction too late in a full-speed
+frame. If the device is still transmitting data when EOF2 for the
+downstream frame occurs, the hub will disable the port. This change is
+not reflected in the hub status endpoint and the device becomes
+unresponsive.
+
+Prevent high-bandwidth transactions from being started too late in a
+frame. The mechanism is not guaranteed: a combination of bit stuffing
+and hub latency may still result in a device overrunning.
+
+fiq_fsm: fix bounce buffer utilisation for Isochronous OUT
+
+Multi-packet isochronous OUT transactions were subject to a few bounday
+bugs. Fix them.
+
+Audio playback is now much more robust: however, an issue stands with
+devices that have adaptive sinks - ALSA plays samples too fast.
+
+dwc_otg: Return full-speed frame numbers in HS mode
+
+The frame counter increments on every *microframe* in high-speed mode.
+Most device drivers expect this number to be in full-speed frames - this
+caused considerable confusion to e.g. snd_usb_audio which uses the
+frame counter to estimate the number of samples played.
+
+fiq_fsm: save PID on completion of interrupt OUT transfers
+
+Also add edge case handling for interrupt transports.
+
+Note that for periodic split IN, data toggles are unimplemented in the
+OTG host hardware - it unconditionally accepts any PID.
+
+fiq_fsm: add missing case for fiq_fsm_tt_in_use()
+
+Certain combinations of bitrate and endpoint activity could
+result in a periodic transaction erroneously getting started
+while the previous Isochronous OUT was still active.
+
+fiq_fsm: clear hcintmsk for aborted transactions
+
+Prevents the FIQ from erroneously handling interrupts
+on a timed out channel.
+
+fiq_fsm: enable by default
+
+fiq_fsm: fix dequeues for non-periodic split transactions
+
+If a dequeue happened between the SSPLIT and CSPLIT phases of the
+transaction, the HCD would never receive an interrupt.
+
+fiq_fsm: Disable by default
+
+fiq_fsm: Handle HC babble errors
+
+The HCTSIZ transfer size field raises a babble interrupt if
+the counter wraps. Handle the resulting interrupt in this case.
+
+dwc_otg: fix interrupt registration for fiq_enable=0
+
+Additionally make the module parameter conditional for wherever
+hcd->fiq_state is touched.
+
+fiq_fsm: Enable by default
+
+dwc_otg: Fix various issues with root port and transaction errors
+
+Process the host port interrupts correctly (and don't trample them).
+Root port hotplug now functional again.
+
+Fix a few thinkos with the transaction error passthrough for fiq_fsm.
+
+fiq_fsm: Implement hack for Split Interrupt transactions
+
+Hubs aren't too picky about which endpoint we send Control type split
+transactions to. By treating Interrupt transfers as Control, it is
+possible to use the non-periodic queue in the OTG core as well as the
+non-periodic FIFOs in the hub itself. This massively reduces the
+microframe exclusivity/contention that periodic split transactions
+otherwise have to enforce.
+
+It goes without saying that this is a fairly egregious USB specification
+violation, but it works.
+
+Original idea by Hans Petter Selasky @ FreeBSD.org.
+
+dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only.
+
+dwc_otg: introduce fiq_fsm_spin(un|)lock()
+
+SMP safety for the FIQ relies on register read-modify write cycles being
+completed in the correct order. Several places in the DWC code modify
+registers also touched by the FIQ. Protect these by a bare-bones lock
+mechanism.
+
+This also makes it possible to run the FIQ and IRQ handlers on different
+cores.
+
+fiq_fsm: fix build on bcm2708 and bcm2709 platforms
+
+dwc_otg: put some barriers back where they should be for UP
+
+bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active
+
+dwc_otg: fixup read-modify-write in critical paths
+
+Be more careful about read-modify-write on registers that the FIQ
+also touches.
+
+Guard fiq_fsm_spin_lock with fiq_enable check
+
+fiq_fsm: Falling out of the state machine isn't fatal
+
+This edge case can be hit if the port is disabled while the FIQ is
+in the middle of a transaction. Make the effects less severe.
+
+Also get rid of the useless return value.
+
+squash: dwc_otg: Allow to build without SMP
+
+usb: core: make overcurrent messages more prominent
+
+Hub overcurrent messages are more serious than "debug". Increase loglevel.
+
+usb: dwc_otg: Don't use dma_to_virt()
+
+Commit 6ce0d20 changes dma_to_virt() which breaks this driver.
+Open code the old dma_to_virt() implementation to work around this.
+
+Limit the use of __bus_to_virt() to cases where transfer_buffer_length
+is set and transfer_buffer is not set. This is done to increase the
+chance that this driver will also work on ARCH_BCM2835.
+
+transfer_buffer should not be NULL if the length is set, but the
+comment in the code indicates that there are situations where this
+might happen. drivers/usb/isp1760/isp1760-hcd.c also has a similar
+comment pointing to a possible: 'usb storage / SCSI bug'.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Fix crash when fiq_enable=0
+
+dwc_otg: fiq_fsm: Make high-speed isochronous strided transfers work properly
+
+Certain low-bandwidth high-speed USB devices (specialist audio devices,
+compressed-frame webcams) have packet intervals > 1 microframe.
+
+Stride these transfers in the FIQ by using the start-of-frame interrupt
+to restart the channel at the right time.
+
+dwc_otg: Force host mode to fix incorrect compute module boards
+
+dwc_otg: Add ARCH_BCM2835 support
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Simplify FIQ irq number code
+
+Dropping ATAGS means we can simplify the FIQ irq number code.
+Also add error checking on the returned irq number.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: Remove duplicate gadget probe/unregister function
+
+dwc_otg: Properly set the HFIR
+
+Douglas Anderson reported:
+
+According to the most up to date version of the dwc2 databook, the FRINT
+field of the HFIR register should be programmed to:
+* 125 us * (PHY clock freq for HS) - 1
+* 1000 us * (PHY clock freq for FS/LS) - 1
+
+This is opposed to older versions of the doc that claimed it should be:
+* 125 us * (PHY clock freq for HS)
+* 1000 us * (PHY clock freq for FS/LS)
+
+and reported lower timing jitter on a USB analyser
+
+dcw_otg: trim xfer length when buffer larger than allocated size is received
+
+dwc_otg: Don't free qh align buffers in atomic context
+
+dwc_otg: Enable the hack for Split Interrupt transactions by default
+
+dwc_otg.fiq_fsm_mask=0xF has long been a suggestion for users with audio stutters or other USB bandwidth issues.
+So far we are aware of many success stories but no failure caused by this setting.
+Make it a default to learn more.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=70437
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+dwc_otg: Use kzalloc when suitable
+
+dwc_otg: Pass struct device to dma_alloc*()
+
+This makes it possible to get the bus address from Device Tree.
+
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+dwc_otg: fix summarize urb->actual_length for isochronous transfers
+
+Kernel does not copy input data of ISO transfers to userspace
+if actual_length is set only in ISO transfers and not summarized
+in urb->actual_length. Fixes raspberrypi/linux#903
+
+fiq_fsm: Use correct states when starting isoc OUT transfers
+
+In fiq_fsm_start_next_periodic() if an isochronous OUT transfer
+was selected, no regard was given as to whether this was a single-packet
+transfer or a multi-packet staged transfer.
+
+For single-packet transfers, this had the effect of repeatedly sending
+OUT packets with bogus data and lengths.
+
+Eventually if the channel was repeatedly enabled enough times, this
+would lock up the OTG core and no further bus transfers would happen.
+
+Set the FSM state up properly if we select a single-packet transfer.
+
+Fixes https://github.com/raspberrypi/linux/issues/1842
+
+dwc_otg: make nak_holdoff work as intended with empty queues
+
+If URBs reading from non-periodic split endpoints were dequeued and
+the last transfer from the endpoint was a NAK handshake, the resulting
+qh->nak_frame value was stale which would result in unnecessarily long
+polling intervals for the first subsequent transfer with a fresh URB.
+
+Fixup qh->nak_frame in dwc_otg_hcd_urb_dequeue and also guard against
+a case where a single URB is submitted to the endpoint, a NAK was
+received on the transfer immediately prior to receiving data and the
+device subsequently resubmits another URB past the qh->nak_frame interval.
+
+Fixes https://github.com/raspberrypi/linux/issues/1709
+
+dwc_otg: fix split transaction data toggle handling around dequeues
+
+See https://github.com/raspberrypi/linux/issues/1709
+
+Fix several issues regarding endpoint state when URBs are dequeued
+- If the HCD is disconnected, flush FIQ-enabled channels properly
+- Save the data toggle state for bulk endpoints if the last transfer
+ from an endpoint where URBs were dequeued returned a data packet
+- Reset hc->start_pkt_count properly in assign_and_init_hc()
+
+dwc_otg: fix several potential crash sources
+
+On root port disconnect events, the host driver state is cleared and
+in-progress host channels are forcibly stopped. This doesn't play
+well with the FIQ running in the background, so:
+- Guard the disconnect callback with both the host spinlock and FIQ
+ spinlock
+- Move qtd dereference in dwc_otg_handle_hc_fsm() after the early-out
+ so we don't dereference a qtd that has gone away
+- Turn catch-all BUG()s in dwc_otg_handle_hc_fsm() into warnings.
+
+dwc_otg: delete hcd->channel_lock
+
+The lock serves no purpose as it is only held while the HCD spinlock
+is already being held.
+
+dwc_otg: remove unnecessary dma-mode channel halts on disconnect interrupt
+
+Host channels are already halted in kill_urbs_in_qh_list() with the
+subsequent interrupt processing behaving as if the URB was dequeued
+via HCD callback.
+
+There's no need to clobber the host channel registers a second time
+as this exposes races between the driver and host channel resulting
+in hcd->free_hc_list becoming corrupted.
+
+dwcotg: Allow to build without FIQ on ARM64
+
+Signed-off-by: popcornmix <popcornmix@gmail.com>
+
+dwc_otg: make periodic scheduling behave properly for FS buses
+
+If the root port is in full-speed mode, transfer times at 12mbit/s
+would be calculated but matched against high-speed quotas.
+
+Reinitialise hcd->frame_usecs[i] on each port enable event so that
+full-speed bandwidth can be tracked sensibly.
+
+Also, don't bother using the FIQ for transfers when in full-speed
+mode - at the slower bus speed, interrupt frequency is reduced by
+an order of magnitude.
+
+Related issue: https://github.com/raspberrypi/linux/issues/2020
+
+dwc_otg: fiq_fsm: Make isochronous compatibility checks work properly
+
+Get rid of the spammy printk and local pointer mangling.
+Also, there is a nominal benefit for using fiq_fsm for isochronous
+transfers in FS mode (~1.1k IRQs per second vs 2.1k IRQs per second)
+so remove the root port speed check.
+
+dwc_otg: add module parameter int_ep_interval_min
+
+Add a module parameter (defaulting to ignored) that clamps the polling rate
+of high-speed Interrupt endpoints to a minimum microframe interval.
+
+The parameter is modifiable at runtime as it is used when activating new
+endpoints (such as on device connect).
+
+dwc_otg: fiq_fsm: Add non-periodic TT exclusivity constraints
+
+Certain hub types do not discriminate between pipe direction (IN or OUT)
+when considering non-periodic transfers. Therefore these hubs get confused
+if multiple transfers are issued in different directions with the same
+device address and endpoint number.
+
+Constrain queuing non-periodic split transactions so they are performed
+serially in such cases.
+
+Related: https://github.com/raspberrypi/linux/issues/2024
+
+dwc_otg: Fixup change to DRIVER_ATTR interface
+
+dwc_otg: Fix compilation warnings
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+
+USB_DWCOTG: Disable building dwc_otg as a module (#2265)
+
+When dwc_otg is built as a module, build will fail with the following
+error:
+
+ERROR: "DWC_TASK_HI_SCHEDULE" [drivers/usb/host/dwc_otg/dwc_otg.ko] undefined!
+scripts/Makefile.modpost:91: recipe for target '__modpost' failed
+make[1]: *** [__modpost] Error 1
+Makefile:1199: recipe for target 'modules' failed
+make: *** [modules] Error 2
+
+Even if the error is solved by including the missing
+DWC_TASK_HI_SCHEDULE function, the kernel will panic when loading
+dwc_otg.
+
+As a workaround, simply prevent user from building dwc_otg as a module
+as the current kernel does not support it.
+
+See: https://github.com/raspberrypi/linux/issues/2258
+
+Signed-off-by: Malik Olivier Boussejra <malik@boussejra.com>
+
+dwc_otg: New timer API
+
+dwc_otg: Fix removed ACCESS_ONCE->READ_ONCE
+
+dwc_otg: don't unconditionally force host mode in dwc_otg_cil_init()
+
+Add the ability to disable force_host_mode for those that want to use
+dwc_otg in both device and host modes.
+
+dwc_otg: Fix a regression when dequeueing isochronous transfers
+
+In 282bed95 (dwc_otg: make nak_holdoff work as intended with empty queues)
+the dequeue mechanism was changed to leave FIQ-enabled transfers to run
+to completion - to avoid leaving hub TT buffers with stale packets lying
+around.
+
+This broke FIQ-accelerated isochronous transfers, as this then meant that
+dozens of transfers were performed after the dequeue function returned.
+
+Restore the state machine fence for isochronous transfers.
+
+fiq_fsm: rewind DMA pointer for OUT transactions that fail (#2288)
+
+See: https://github.com/raspberrypi/linux/issues/2140
+
+dwc_otg: add smp_mb() to prevent driver state corruption on boot
+
+Occasional crashes have been seen where the FIQ code dereferences
+invalid/random pointers immediately after being set up, leading to
+panic on boot.
+
+The crash occurs as the FIQ code races against hcd_init_fiq() and
+the hcd_init_fiq() code races against the outstanding memory stores
+from dwc_otg_hcd_init(). Use explicit barriers after touching
+driver state.
+
+usb: dwc_otg: fix memory corruption in dwc_otg driver
+
+[Upstream commit 51b1b6491752ac066ee8d32cc66042fcc955fef6]
+
+The move from the staging tree to the main tree exposed a
+longstanding memory corruption bug in the dwc2 driver. The
+reordering of the driver initialization caused the dwc2 driver
+to corrupt the initialization data of the sdhci driver on the
+Raspberry Pi platform, which made the bug show up.
+
+The error is in calling to_usb_device(hsotg->dev), since ->dev
+is not a member of struct usb_device. The easiest fix is to
+just remove the offending code, since it is not really needed.
+
+Thanks to Stephen Warren for tracking down the cause of this.
+
+Reported-by: Andre Heider <a.heider@gmail.com>
+Tested-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Paul Zimmerman <paulz@synopsys.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[lukas: port from upstream dwc2 to out-of-tree dwc_otg driver]
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+
+usb: dwb_otg: Fix unreachable switch statement warning
+
+This warning appears with GCC 7.3.0 from toolchains.bootlin.com:
+
+../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c: In function ‘fiq_fsm_update_hs_isoc’:
+../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c:595:61: warning: statement will never be executed [-Wswitch-unreachable]
+ st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps;
+ ~~~~~~~~~~~~~~~~~^~~~
+
+Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
+
+dwc_otg: fiq_fsm: fix incorrect DMA register offset calculation
+
+Rationalise the offset and update all call sites.
+
+Fixes https://github.com/raspberrypi/linux/issues/2408
+
+dwc_otg: fix bug with port_addr assignment for single-TT hubs
+
+See https://github.com/raspberrypi/linux/issues/2734
+
+The "Hub Port" field in the split transaction packet was always set
+to 1 for single-TT hubs. The majority of single-TT hub products
+apparently ignore this field and broadcast to all downstream enabled
+ports, which masked the issue. A subset of hub devices apparently
+need the port number to be exact or split transactions will fail.
+
+usb: dwc_otg: Clean up build warnings on 64bit kernels
+
+No functional changes. Almost all are changes to logging lines.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+
+usb: dwc_otg: Use dma allocation for mphi dummy_send buffer
+
+The FIQ driver used a kzalloc'ed buffer for dummy_send,
+passing a kernel virtual address to the hardware block.
+The buffer is only ever used for a dummy read, so it
+should be harmless, but there is the chance that it will
+cause exceptions.
+
+Use a dma allocation so that we have a genuine bus address,
+and read from that.
+Free the allocation when done for good measure.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
+
+dwc_otg: only do_split when we actually need to do a split
+
+The previous test would fail if the root port was in fullspeed mode
+and there was a hub between the FS device and the root port. While
+the transfer worked, the schedule mangling performed for high-speed
+split transfers would break leading to an 8ms polling interval.
+
+dwc_otg: fix locking around dequeueing and killing URBs
+
+kill_urbs_in_qh_list() is practically only ever called with the fiq lock
+already held, so don't spinlock twice in the case where we need to cancel
+an isochronous transfer.
+
+Also fix up a case where the global interrupt register could be read with
+the fiq lock not held.
+
+Fixes the deadlock seen in https://github.com/raspberrypi/linux/issues/2907
+---
+ arch/arm/include/asm/irqflags.h | 16 +-
+ arch/arm/kernel/fiqasm.S | 4 +
+ drivers/usb/Makefile | 1 +
+ drivers/usb/core/generic.c | 1 +
+ drivers/usb/core/hub.c | 2 +-
+ drivers/usb/core/message.c | 79 +
+ drivers/usb/core/otg_whitelist.h | 114 +-
+ drivers/usb/gadget/file_storage.c | 3676 +++++++++
+ drivers/usb/host/Kconfig | 10 +
+ drivers/usb/host/Makefile | 2 +
+ drivers/usb/host/dwc_common_port/Makefile | 58 +
+ .../usb/host/dwc_common_port/Makefile.fbsd | 17 +
+ .../usb/host/dwc_common_port/Makefile.linux | 49 +
+ drivers/usb/host/dwc_common_port/changes.txt | 174 +
+ .../usb/host/dwc_common_port/doc/doxygen.cfg | 270 +
+ drivers/usb/host/dwc_common_port/dwc_cc.c | 532 ++
+ drivers/usb/host/dwc_common_port/dwc_cc.h | 224 +
+ .../host/dwc_common_port/dwc_common_fbsd.c | 1308 +++
+ .../host/dwc_common_port/dwc_common_linux.c | 1409 ++++
+ .../host/dwc_common_port/dwc_common_nbsd.c | 1275 +++
+ drivers/usb/host/dwc_common_port/dwc_crypto.c | 308 +
+ drivers/usb/host/dwc_common_port/dwc_crypto.h | 111 +
+ drivers/usb/host/dwc_common_port/dwc_dh.c | 291 +
+ drivers/usb/host/dwc_common_port/dwc_dh.h | 106 +
+ drivers/usb/host/dwc_common_port/dwc_list.h | 594 ++
+ drivers/usb/host/dwc_common_port/dwc_mem.c | 245 +
+ drivers/usb/host/dwc_common_port/dwc_modpow.c | 636 ++
+ drivers/usb/host/dwc_common_port/dwc_modpow.h | 34 +
+ .../usb/host/dwc_common_port/dwc_notifier.c | 319 +
+ .../usb/host/dwc_common_port/dwc_notifier.h | 122 +
+ drivers/usb/host/dwc_common_port/dwc_os.h | 1276 +++
+ drivers/usb/host/dwc_common_port/usb.h | 946 +++
+ drivers/usb/host/dwc_otg/Makefile | 82 +
+ drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 +
+ drivers/usb/host/dwc_otg/dummy_audio.c | 1574 ++++
+ drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 +
+ drivers/usb/host/dwc_otg/dwc_otg_adp.c | 854 ++
+ drivers/usb/host/dwc_otg/dwc_otg_adp.h | 80 +
+ drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1212 +++
+ drivers/usb/host/dwc_otg/dwc_otg_attr.h | 89 +
+ drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 +++++
+ drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 320 +
+ drivers/usb/host/dwc_otg/dwc_otg_cil.c | 7146 +++++++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1464 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 1601 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 705 ++
+ drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 117 +
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1766 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_driver.h | 86 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1401 ++++
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 373 +
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S | 80 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4305 ++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 870 ++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1134 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 417 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2752 +++++++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 1000 +++
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 970 +++
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 188 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2725 +++++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 273 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 361 +
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 5148 ++++++++++++
+ drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1280 +++
+ drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2550 ++++++
+ drivers/usb/host/dwc_otg/test/Makefile | 16 +
+ drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 +
+ .../usb/host/dwc_otg/test/test_mod_param.pl | 133 +
+ drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 +
+ 70 files changed, 60037 insertions(+), 16 deletions(-)
+
+diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h
+index aeec7f24eb75..a3b186608c60 100644
+--- a/arch/arm/include/asm/irqflags.h
++++ b/arch/arm/include/asm/irqflags.h
+@@ -163,13 +163,23 @@ static inline unsigned long arch_local_save_flags(void)
+ }
+
+ /*
+- * restore saved IRQ & FIQ state
++ * restore saved IRQ state
+ */
+ #define arch_local_irq_restore arch_local_irq_restore
+ static inline void arch_local_irq_restore(unsigned long flags)
+ {
+- asm volatile(
+- " msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore"
++ unsigned long temp = 0;
++ flags &= ~(1 << 6);
++ asm volatile (
++ " mrs %0, cpsr"
++ : "=r" (temp)
++ :
++ : "memory", "cc");
++ /* Preserve FIQ bit */
++ temp &= (1 << 6);
++ flags = flags | temp;
++ asm volatile (
++ " msr cpsr_c, %0 @ local_irq_restore"
+ :
+ : "r" (flags)
+ : "memory", "cc");
+diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S
+index 8dd26e1a9bd6..eef484756af2 100644
+--- a/arch/arm/kernel/fiqasm.S
++++ b/arch/arm/kernel/fiqasm.S
+@@ -47,3 +47,7 @@ ENTRY(__get_fiq_regs)
+ mov r0, r0 @ avoid hazard prior to ARMv4
+ ret lr
+ ENDPROC(__get_fiq_regs)
++
++ENTRY(__FIQ_Branch)
++ mov pc, r8
++ENDPROC(__FIQ_Branch)
+diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
+index 7d1b8c82b208..2810d7153f57 100644
+--- a/drivers/usb/Makefile
++++ b/drivers/usb/Makefile
+@@ -8,6 +8,7 @@
+ obj-$(CONFIG_USB) += core/
+ obj-$(CONFIG_USB_SUPPORT) += phy/
+
++obj-$(CONFIG_USB_DWCOTG) += host/
+ obj-$(CONFIG_USB_DWC3) += dwc3/
+ obj-$(CONFIG_USB_DWC2) += dwc2/
+ obj-$(CONFIG_USB_ISP1760) += isp1760/
+diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
+index 1ac9c1e5f773..62070ef0afb4 100644
+--- a/drivers/usb/core/generic.c
++++ b/drivers/usb/core/generic.c
+@@ -190,6 +190,7 @@ int usb_choose_configuration(struct usb_device *udev)
+ dev_warn(&udev->dev,
+ "no configuration chosen from %d choice%s\n",
+ num_configs, plural(num_configs));
++ dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA);
+ }
+ return i;
+ }
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 8d4631c81b9f..7a1b4bd94c57 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -5286,7 +5286,7 @@ static void port_event(struct usb_hub *hub, int port1)
+ port_dev->over_current_count++;
+ port_over_current_notify(port_dev);
+
+- dev_dbg(&port_dev->dev, "over-current change #%u\n",
++ dev_notice(&port_dev->dev, "over-current change #%u\n",
+ port_dev->over_current_count);
+ usb_clear_port_feature(hdev, port1,
+ USB_PORT_FEAT_C_OVER_CURRENT);
+diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
+index e844bb7b5676..50bf00e38f0d 100644
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -1993,6 +1993,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
+ if (cp->string == NULL &&
+ !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
+ cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
++/* Uncomment this define to enable the HS Electrical Test support */
++#define DWC_HS_ELECT_TST 1
++#ifdef DWC_HS_ELECT_TST
++ /* Here we implement the HS Electrical Test support. The
++ * tester uses a vendor ID of 0x1A0A to indicate we should
++ * run a special test sequence. The product ID tells us
++ * which sequence to run. We invoke the test sequence by
++ * sending a non-standard SetFeature command to our root
++ * hub port. Our dwc_otg_hcd_hub_control() routine will
++ * recognize the command and perform the desired test
++ * sequence.
++ */
++ if (dev->descriptor.idVendor == 0x1A0A) {
++ /* HSOTG Electrical Test */
++ dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n");
++
++ if (dev->bus && dev->bus->root_hub) {
++ struct usb_device *hdev = dev->bus->root_hub;
++ dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct);
++
++ switch (dev->descriptor.idProduct) {
++ case 0x0101: /* TEST_SE0_NAK */
++ dev_warn(&dev->dev, "TEST_SE0_NAK\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ);
++ break;
++
++ case 0x0102: /* TEST_J */
++ dev_warn(&dev->dev, "TEST_J\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ);
++ break;
++
++ case 0x0103: /* TEST_K */
++ dev_warn(&dev->dev, "TEST_K\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ);
++ break;
++
++ case 0x0104: /* TEST_PACKET */
++ dev_warn(&dev->dev, "TEST_PACKET\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ);
++ break;
++
++ case 0x0105: /* TEST_FORCE_ENABLE */
++ dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ);
++ break;
++
++ case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */
++ dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ);
++ break;
++
++ case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
++ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ);
++ break;
++
++ case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
++ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n");
++ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
++ USB_REQ_SET_FEATURE, USB_RT_PORT,
++ USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ);
++ }
++ }
++ }
++#endif /* DWC_HS_ELECT_TST */
+
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
+index 2ae90158ded7..150d4fa1e09b 100644
+--- a/drivers/usb/core/otg_whitelist.h
++++ b/drivers/usb/core/otg_whitelist.h
+@@ -15,33 +15,82 @@
+ static struct usb_device_id whitelist_table[] = {
+
+ /* hubs are optional in OTG, but very handy ... */
++#define CERT_WITHOUT_HUBS
++#if defined(CERT_WITHOUT_HUBS)
++{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/
++#else
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
+ { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
++{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), },
++#endif
+
+ #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
+ /* FIXME actually, printers are NOT supposed to use device classes;
+ * they're supposed to use interface classes...
+ */
+-{ USB_DEVICE_INFO(7, 1, 1) },
+-{ USB_DEVICE_INFO(7, 1, 2) },
+-{ USB_DEVICE_INFO(7, 1, 3) },
++//{ USB_DEVICE_INFO(7, 1, 1) },
++//{ USB_DEVICE_INFO(7, 1, 2) },
++//{ USB_DEVICE_INFO(7, 1, 3) },
+ #endif
+
+ #ifdef CONFIG_USB_NET_CDCETHER
+ /* Linux-USB CDC Ethernet gadget */
+-{ USB_DEVICE(0x0525, 0xa4a1), },
++//{ USB_DEVICE(0x0525, 0xa4a1), },
+ /* Linux-USB CDC Ethernet + RNDIS gadget */
+-{ USB_DEVICE(0x0525, 0xa4a2), },
++//{ USB_DEVICE(0x0525, 0xa4a2), },
+ #endif
+
+ #if IS_ENABLED(CONFIG_USB_TEST)
+ /* gadget zero, for testing */
+-{ USB_DEVICE(0x0525, 0xa4a0), },
++//{ USB_DEVICE(0x0525, 0xa4a0), },
+ #endif
+
++/* OPT Tester */
++{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */
++{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */
++{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */
++{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */
++{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */
++{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */
++{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */
++{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */
++
++/* Sony cameras */
++{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), },
++
++/* Memory Devices */
++//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */
++//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */
++//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */
++//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */
++{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/
++//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */
++
++/* HP Printers */
++//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */
++//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */
++
++/* Speakers */
++//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */
++//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */
++
+ { } /* Terminating entry */
+ };
+
++static inline void report_errors(struct usb_device *dev)
++{
++ /* OTG MESSAGE: report errors here, customize to match your product */
++ dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n",
++ le16_to_cpu(dev->descriptor.idVendor),
++ le16_to_cpu(dev->descriptor.idProduct));
++ if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){
++ dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n");
++ } else {
++ dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n");
++ }
++}
++
++
+ static int is_targeted(struct usb_device *dev)
+ {
+ struct usb_device_id *id = whitelist_table;
+@@ -91,16 +140,57 @@ static int is_targeted(struct usb_device *dev)
+ continue;
+
+ return 1;
++ /* NOTE: can't use usb_match_id() since interface caches
++ * aren't set up yet. this is cut/paste from that code.
++ */
++ for (id = whitelist_table; id->match_flags; id++) {
++#ifdef DEBUG
++ dev_dbg(&dev->dev,
++ "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n",
++ id->idVendor,
++ id->idProduct,
++ id->bDeviceClass,
++ id->bDeviceSubClass,
++ id->bDeviceProtocol);
++#endif
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
++ id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
++ id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
++ continue;
++
++ /* No need to test id->bcdDevice_lo != 0, since 0 is never
++ greater than any unsigned number. */
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
++ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
++ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
++ (id->bDeviceClass != dev->descriptor.bDeviceClass))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
++ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
++ continue;
++
++ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
++ (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
++ continue;
++
++ return 1;
++ }
+ }
+
+ /* add other match criteria here ... */
+
+-
+- /* OTG MESSAGE: report errors here, customize to match your product */
+- dev_err(&dev->dev, "device v%04x p%04x is not supported\n",
+- le16_to_cpu(dev->descriptor.idVendor),
+- le16_to_cpu(dev->descriptor.idProduct));
+-
++ report_errors(dev);
+ return 0;
+ }
+
+diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
+new file mode 100644
+index 000000000000..a896d73f7a93
+--- /dev/null
++++ b/drivers/usb/gadget/file_storage.c
+@@ -0,0 +1,3676 @@
++/*
++ * file_storage.c -- File-backed USB Storage Gadget, for USB development
++ *
++ * Copyright (C) 2003-2008 Alan Stern
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++++
++
++/*
++ * The File-backed Storage Gadget acts as a USB Mass Storage device,
++ * appearing to the host as a disk drive or as a CD-ROM drive. In addition
++ * to providing an example of a genuinely useful gadget driver for a USB
++ * device, it also illustrates a technique of double-buffering for increased
++ * throughput. Last but not least, it gives an easy way to probe the
++ * behavior of the Mass Storage drivers in a USB host.
++ *
++ * Backing storage is provided by a regular file or a block device, specified
++ * by the "file" module parameter. Access can be limited to read-only by
++ * setting the optional "ro" module parameter. (For CD-ROM emulation,
++ * access is always read-only.) The gadget will indicate that it has
++ * removable media if the optional "removable" module parameter is set.
++ *
++ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
++ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
++ * by the optional "transport" module parameter. It also supports the
++ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
++ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
++ * the optional "protocol" module parameter. In addition, the default
++ * Vendor ID, Product ID, release number and serial number can be overridden.
++ *
++ * There is support for multiple logical units (LUNs), each of which has
++ * its own backing file. The number of LUNs can be set using the optional
++ * "luns" module parameter (anywhere from 1 to 8), and the corresponding
++ * files are specified using comma-separated lists for "file" and "ro".
++ * The default number of LUNs is taken from the number of "file" elements;
++ * it is 1 if "file" is not given. If "removable" is not set then a backing
++ * file must be specified for each LUN. If it is set, then an unspecified
++ * or empty backing filename means the LUN's medium is not loaded. Ideally
++ * each LUN would be settable independently as a disk drive or a CD-ROM
++ * drive, but currently all LUNs have to be the same type. The CD-ROM
++ * emulation includes a single data track and no audio tracks; hence there
++ * need be only one backing file per LUN.
++ *
++ * Requirements are modest; only a bulk-in and a bulk-out endpoint are
++ * needed (an interrupt-out endpoint is also needed for CBI). The memory
++ * requirement amounts to two 16K buffers, size configurable by a parameter.
++ * Support is included for both full-speed and high-speed operation.
++ *
++ * Note that the driver is slightly non-portable in that it assumes a
++ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and
++ * interrupt-in endpoints. With most device controllers this isn't an
++ * issue, but there may be some with hardware restrictions that prevent
++ * a buffer from being used by more than one endpoint.
++ *
++ * Module options:
++ *
++ * file=filename[,filename...]
++ * Required if "removable" is not set, names of
++ * the files or block devices used for
++ * backing storage
++ * serial=HHHH... Required serial number (string of hex chars)
++ * ro=b[,b...] Default false, booleans for read-only access
++ * removable Default false, boolean for removable media
++ * luns=N Default N = number of filenames, number of
++ * LUNs to support
++ * nofua=b[,b...] Default false, booleans for ignore FUA flag
++ * in SCSI WRITE(10,12) commands
++ * stall Default determined according to the type of
++ * USB device controller (usually true),
++ * boolean to permit the driver to halt
++ * bulk endpoints
++ * cdrom Default false, boolean for whether to emulate
++ * a CD-ROM drive
++ * transport=XXX Default BBB, transport name (CB, CBI, or BBB)
++ * protocol=YYY Default SCSI, protocol name (RBC, 8020 or
++ * ATAPI, QIC, UFI, 8070, or SCSI;
++ * also 1 - 6)
++ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
++ * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
++ * release=0xRRRR Override the USB release number (bcdDevice)
++ * buflen=N Default N=16384, buffer size used (will be
++ * rounded down to a multiple of
++ * PAGE_CACHE_SIZE)
++ *
++ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
++ * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
++ * default values are used for everything else.
++ *
++ * The pathnames of the backing files and the ro settings are available in
++ * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
++ * the gadget's sysfs directory. If the "removable" option is set, writing to
++ * these files will simulate ejecting/loading the medium (writing an empty
++ * line means eject) and adjusting a write-enable tab. Changes to the ro
++ * setting are not allowed when the medium is loaded or if CD-ROM emulation
++ * is being used.
++ *
++ * This gadget driver is heavily based on "Gadget Zero" by David Brownell.
++ * The driver's SCSI command interface was based on the "Information
++ * technology - Small Computer System Interface - 2" document from
++ * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at
++ * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception
++ * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the
++ * "Universal Serial Bus Mass Storage Class UFI Command Specification"
++ * document, Revision 1.0, December 14, 1998, available at
++ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
++ */
++
++
++/*
++ * Driver Design
++ *
++ * The FSG driver is fairly straightforward. There is a main kernel
++ * thread that handles most of the work. Interrupt routines field
++ * callbacks from the controller driver: bulk- and interrupt-request
++ * completion notifications, endpoint-0 events, and disconnect events.
++ * Completion events are passed to the main thread by wakeup calls. Many
++ * ep0 requests are handled at interrupt time, but SetInterface,
++ * SetConfiguration, and device reset requests are forwarded to the
++ * thread in the form of "exceptions" using SIGUSR1 signals (since they
++ * should interrupt any ongoing file I/O operations).
++ *
++ * The thread's main routine implements the standard command/data/status
++ * parts of a SCSI interaction. It and its subroutines are full of tests
++ * for pending signals/exceptions -- all this polling is necessary since
++ * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
++ * indication that the driver really wants to be running in userspace.)
++ * An important point is that so long as the thread is alive it keeps an
++ * open reference to the backing file. This will prevent unmounting
++ * the backing file's underlying filesystem and could cause problems
++ * during system shutdown, for example. To prevent such problems, the
++ * thread catches INT, TERM, and KILL signals and converts them into
++ * an EXIT exception.
++ *
++ * In normal operation the main thread is started during the gadget's
++ * fsg_bind() callback and stopped during fsg_unbind(). But it can also
++ * exit when it receives a signal, and there's no point leaving the
++ * gadget running when the thread is dead. So just before the thread
++ * exits, it deregisters the gadget driver. This makes things a little
++ * tricky: The driver is deregistered at two places, and the exiting
++ * thread can indirectly call fsg_unbind() which in turn can tell the
++ * thread to exit. The first problem is resolved through the use of the
++ * REGISTERED atomic bitflag; the driver will only be deregistered once.
++ * The second problem is resolved by having fsg_unbind() check
++ * fsg->state; it won't try to stop the thread if the state is already
++ * FSG_STATE_TERMINATED.
++ *
++ * To provide maximum throughput, the driver uses a circular pipeline of
++ * buffer heads (struct fsg_buffhd). In principle the pipeline can be
++ * arbitrarily long; in practice the benefits don't justify having more
++ * than 2 stages (i.e., double buffering). But it helps to think of the
++ * pipeline as being a long one. Each buffer head contains a bulk-in and
++ * a bulk-out request pointer (since the buffer can be used for both
++ * output and input -- directions always are given from the host's
++ * point of view) as well as a pointer to the buffer and various state
++ * variables.
++ *
++ * Use of the pipeline follows a simple protocol. There is a variable
++ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
++ * At any time that buffer head may still be in use from an earlier
++ * request, so each buffer head has a state variable indicating whether
++ * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
++ * buffer head to be EMPTY, filling the buffer either by file I/O or by
++ * USB I/O (during which the buffer head is BUSY), and marking the buffer
++ * head FULL when the I/O is complete. Then the buffer will be emptied
++ * (again possibly by USB I/O, during which it is marked BUSY) and
++ * finally marked EMPTY again (possibly by a completion routine).
++ *
++ * A module parameter tells the driver to avoid stalling the bulk
++ * endpoints wherever the transport specification allows. This is
++ * necessary for some UDCs like the SuperH, which cannot reliably clear a
++ * halt on a bulk endpoint. However, under certain circumstances the
++ * Bulk-only specification requires a stall. In such cases the driver
++ * will halt the endpoint and set a flag indicating that it should clear
++ * the halt in software during the next device reset. Hopefully this
++ * will permit everything to work correctly. Furthermore, although the
++ * specification allows the bulk-out endpoint to halt when the host sends
++ * too much data, implementing this would cause an unavoidable race.
++ * The driver will always use the "no-stall" approach for OUT transfers.
++ *
++ * One subtle point concerns sending status-stage responses for ep0
++ * requests. Some of these requests, such as device reset, can involve
++ * interrupting an ongoing file I/O operation, which might take an
++ * arbitrarily long time. During that delay the host might give up on
++ * the original ep0 request and issue a new one. When that happens the
++ * driver should not notify the host about completion of the original
++ * request, as the host will no longer be waiting for it. So the driver
++ * assigns to each ep0 request a unique tag, and it keeps track of the
++ * tag value of the request associated with a long-running exception
++ * (device-reset, interface-change, or configuration-change). When the
++ * exception handler is finished, the status-stage response is submitted
++ * only if the current ep0 request tag is equal to the exception request
++ * tag. Thus only the most recently received ep0 request will get a
++ * status-stage response.
++ *
++ * Warning: This driver source file is too long. It ought to be split up
++ * into a header file plus about 3 separate .c files, to handle the details
++ * of the Gadget, USB Mass Storage, and SCSI protocols.
++ */
++
++
++/* #define VERBOSE_DEBUG */
++/* #define DUMP_MSGS */
++
++
++#include <linux/blkdev.h>
++#include <linux/completion.h>
++#include <linux/dcache.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fcntl.h>
++#include <linux/file.h>
++#include <linux/fs.h>
++#include <linux/kref.h>
++#include <linux/kthread.h>
++#include <linux/limits.h>
++#include <linux/module.h>
++#include <linux/rwsem.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/freezer.h>
++#include <linux/utsname.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "gadget_chips.h"
++
++
++
++/*
++ * Kbuild is not very cooperative with respect to linking separately
++ * compiled library objects into one module. So for now we won't use
++ * separate compilation ... ensuring init/exit sections work to shrink
++ * the runtime footprint, and giving us at least some parts of what
++ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
++ */
++#include "usbstring.c"
++#include "config.c"
++#include "epautoconf.c"
++
++/*-------------------------------------------------------------------------*/
++
++#define DRIVER_DESC "File-backed Storage Gadget"
++#define DRIVER_NAME "g_file_storage"
++#define DRIVER_VERSION "1 September 2010"
++
++static char fsg_string_manufacturer[64];
++static const char fsg_string_product[] = DRIVER_DESC;
++static const char fsg_string_config[] = "Self-powered";
++static const char fsg_string_interface[] = "Mass Storage";
++
++
++#include "storage_common.c"
++
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR("Alan Stern");
++MODULE_LICENSE("Dual BSD/GPL");
++
++/*
++ * This driver assumes self-powered hardware and has no way for users to
++ * trigger remote wakeup. It uses autoconfiguration to select endpoints
++ * and endpoint addresses.
++ */
++
++
++/*-------------------------------------------------------------------------*/
++
++
++/* Encapsulate the module parameter settings */
++
++static struct {
++ char *file[FSG_MAX_LUNS];
++ char *serial;
++ bool ro[FSG_MAX_LUNS];
++ bool nofua[FSG_MAX_LUNS];
++ unsigned int num_filenames;
++ unsigned int num_ros;
++ unsigned int num_nofuas;
++ unsigned int nluns;
++
++ bool removable;
++ bool can_stall;
++ bool cdrom;
++
++ char *transport_parm;
++ char *protocol_parm;
++ unsigned short vendor;
++ unsigned short product;
++ unsigned short release;
++ unsigned int buflen;
++
++ int transport_type;
++ char *transport_name;
++ int protocol_type;
++ char *protocol_name;
++
++} mod_data = { // Default values
++ .transport_parm = "BBB",
++ .protocol_parm = "SCSI",
++ .removable = 0,
++ .can_stall = 1,
++ .cdrom = 0,
++ .vendor = FSG_VENDOR_ID,
++ .product = FSG_PRODUCT_ID,
++ .release = 0xffff, // Use controller chip type
++ .buflen = 16384,
++ };
++
++
++module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
++ S_IRUGO);
++MODULE_PARM_DESC(file, "names of backing files or devices");
++
++module_param_named(serial, mod_data.serial, charp, S_IRUGO);
++MODULE_PARM_DESC(serial, "USB serial number");
++
++module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
++MODULE_PARM_DESC(ro, "true to force read-only");
++
++module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
++ S_IRUGO);
++MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
++
++module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
++MODULE_PARM_DESC(luns, "number of LUNs");
++
++module_param_named(removable, mod_data.removable, bool, S_IRUGO);
++MODULE_PARM_DESC(removable, "true to simulate removable media");
++
++module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
++MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
++
++module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
++MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
++
++/* In the non-TEST version, only the module parameters listed above
++ * are available. */
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++
++module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
++MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
++
++module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
++MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
++ "8070, or SCSI)");
++
++module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
++MODULE_PARM_DESC(vendor, "USB Vendor ID");
++
++module_param_named(product, mod_data.product, ushort, S_IRUGO);
++MODULE_PARM_DESC(product, "USB Product ID");
++
++module_param_named(release, mod_data.release, ushort, S_IRUGO);
++MODULE_PARM_DESC(release, "USB release number");
++
++module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
++MODULE_PARM_DESC(buflen, "I/O buffer size");
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*
++ * These definitions will permit the compiler to avoid generating code for
++ * parts of the driver that aren't used in the non-TEST version. Even gcc
++ * can recognize when a test of a constant expression yields a dead code
++ * path.
++ */
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++
++#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK)
++#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI)
++#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI)
++
++#else
++
++#define transport_is_bbb() 1
++#define transport_is_cbi() 0
++#define protocol_is_scsi() 1
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*-------------------------------------------------------------------------*/
++
++
++struct fsg_dev {
++ /* lock protects: state, all the req_busy's, and cbbuf_cmnd */
++ spinlock_t lock;
++ struct usb_gadget *gadget;
++
++ /* filesem protects: backing files in use */
++ struct rw_semaphore filesem;
++
++ /* reference counting: wait until all LUNs are released */
++ struct kref ref;
++
++ struct usb_ep *ep0; // Handy copy of gadget->ep0
++ struct usb_request *ep0req; // For control responses
++ unsigned int ep0_req_tag;
++ const char *ep0req_name;
++
++ struct usb_request *intreq; // For interrupt responses
++ int intreq_busy;
++ struct fsg_buffhd *intr_buffhd;
++
++ unsigned int bulk_out_maxpacket;
++ enum fsg_state state; // For exception handling
++ unsigned int exception_req_tag;
++
++ u8 config, new_config;
++
++ unsigned int running : 1;
++ unsigned int bulk_in_enabled : 1;
++ unsigned int bulk_out_enabled : 1;
++ unsigned int intr_in_enabled : 1;
++ unsigned int phase_error : 1;
++ unsigned int short_packet_received : 1;
++ unsigned int bad_lun_okay : 1;
++
++ unsigned long atomic_bitflags;
++#define REGISTERED 0
++#define IGNORE_BULK_OUT 1
++#define SUSPENDED 2
++
++ struct usb_ep *bulk_in;
++ struct usb_ep *bulk_out;
++ struct usb_ep *intr_in;
++
++ struct fsg_buffhd *next_buffhd_to_fill;
++ struct fsg_buffhd *next_buffhd_to_drain;
++
++ int thread_wakeup_needed;
++ struct completion thread_notifier;
++ struct task_struct *thread_task;
++
++ int cmnd_size;
++ u8 cmnd[MAX_COMMAND_SIZE];
++ enum data_direction data_dir;
++ u32 data_size;
++ u32 data_size_from_cmnd;
++ u32 tag;
++ unsigned int lun;
++ u32 residue;
++ u32 usb_amount_left;
++
++ /* The CB protocol offers no way for a host to know when a command
++ * has completed. As a result the next command may arrive early,
++ * and we will still have to handle it. For that reason we need
++ * a buffer to store new commands when using CB (or CBI, which
++ * does not oblige a host to wait for command completion either). */
++ int cbbuf_cmnd_size;
++ u8 cbbuf_cmnd[MAX_COMMAND_SIZE];
++
++ unsigned int nluns;
++ struct fsg_lun *luns;
++ struct fsg_lun *curlun;
++ /* Must be the last entry */
++ struct fsg_buffhd buffhds[];
++};
++
++typedef void (*fsg_routine_t)(struct fsg_dev *);
++
++static int exception_in_progress(struct fsg_dev *fsg)
++{
++ return (fsg->state > FSG_STATE_IDLE);
++}
++
++/* Make bulk-out requests be divisible by the maxpacket size */
++static void set_bulk_out_req_length(struct fsg_dev *fsg,
++ struct fsg_buffhd *bh, unsigned int length)
++{
++ unsigned int rem;
++
++ bh->bulk_out_intended_length = length;
++ rem = length % fsg->bulk_out_maxpacket;
++ if (rem > 0)
++ length += fsg->bulk_out_maxpacket - rem;
++ bh->outreq->length = length;
++}
++
++static struct fsg_dev *the_fsg;
++static struct usb_gadget_driver fsg_driver;
++
++
++/*-------------------------------------------------------------------------*/
++
++static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
++{
++ const char *name;
++
++ if (ep == fsg->bulk_in)
++ name = "bulk-in";
++ else if (ep == fsg->bulk_out)
++ name = "bulk-out";
++ else
++ name = ep->name;
++ DBG(fsg, "%s set halt\n", name);
++ return usb_ep_set_halt(ep);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * DESCRIPTORS ... most are static, but strings and (full) configuration
++ * descriptors are built on demand. Also the (static) config and interface
++ * descriptors are adjusted during fsg_bind().
++ */
++
++/* There is only one configuration. */
++#define CONFIG_VALUE 1
++
++static struct usb_device_descriptor
++device_desc = {
++ .bLength = sizeof device_desc,
++ .bDescriptorType = USB_DT_DEVICE,
++
++ .bcdUSB = cpu_to_le16(0x0200),
++ .bDeviceClass = USB_CLASS_PER_INTERFACE,
++
++ /* The next three values can be overridden by module parameters */
++ .idVendor = cpu_to_le16(FSG_VENDOR_ID),
++ .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
++ .bcdDevice = cpu_to_le16(0xffff),
++
++ .iManufacturer = FSG_STRING_MANUFACTURER,
++ .iProduct = FSG_STRING_PRODUCT,
++ .iSerialNumber = FSG_STRING_SERIAL,
++ .bNumConfigurations = 1,
++};
++
++static struct usb_config_descriptor
++config_desc = {
++ .bLength = sizeof config_desc,
++ .bDescriptorType = USB_DT_CONFIG,
++
++ /* wTotalLength computed by usb_gadget_config_buf() */
++ .bNumInterfaces = 1,
++ .bConfigurationValue = CONFIG_VALUE,
++ .iConfiguration = FSG_STRING_CONFIG,
++ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
++ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
++};
++
++
++static struct usb_qualifier_descriptor
++dev_qualifier = {
++ .bLength = sizeof dev_qualifier,
++ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
++
++ .bcdUSB = cpu_to_le16(0x0200),
++ .bDeviceClass = USB_CLASS_PER_INTERFACE,
++
++ .bNumConfigurations = 1,
++};
++
++static int populate_bos(struct fsg_dev *fsg, u8 *buf)
++{
++ memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
++ buf += USB_DT_BOS_SIZE;
++
++ memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
++ buf += USB_DT_USB_EXT_CAP_SIZE;
++
++ memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
++
++ return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
++ + USB_DT_USB_EXT_CAP_SIZE;
++}
++
++/*
++ * Config descriptors must agree with the code that sets configurations
++ * and with code managing interfaces and their altsettings. They must
++ * also handle different speeds and other-speed requests.
++ */
++static int populate_config_buf(struct usb_gadget *gadget,
++ u8 *buf, u8 type, unsigned index)
++{
++ enum usb_device_speed speed = gadget->speed;
++ int len;
++ const struct usb_descriptor_header **function;
++
++ if (index > 0)
++ return -EINVAL;
++
++ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
++ speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
++ function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH
++ ? (const struct usb_descriptor_header **)fsg_hs_function
++ : (const struct usb_descriptor_header **)fsg_fs_function;
++
++ /* for now, don't advertise srp-only devices */
++ if (!gadget_is_otg(gadget))
++ function++;
++
++ len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
++ ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
++ return len;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* These routines may be called in process context or in_irq */
++
++/* Caller must hold fsg->lock */
++static void wakeup_thread(struct fsg_dev *fsg)
++{
++ /* Tell the main thread that something has happened */
++ fsg->thread_wakeup_needed = 1;
++ if (fsg->thread_task)
++ wake_up_process(fsg->thread_task);
++}
++
++
++static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
++{
++ unsigned long flags;
++
++ /* Do nothing if a higher-priority exception is already in progress.
++ * If a lower-or-equal priority exception is in progress, preempt it
++ * and notify the main thread by sending it a signal. */
++ spin_lock_irqsave(&fsg->lock, flags);
++ if (fsg->state <= new_state) {
++ fsg->exception_req_tag = fsg->ep0_req_tag;
++ fsg->state = new_state;
++ if (fsg->thread_task)
++ send_sig_info(SIGUSR1, SEND_SIG_FORCED,
++ fsg->thread_task);
++ }
++ spin_unlock_irqrestore(&fsg->lock, flags);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* The disconnect callback and ep0 routines. These always run in_irq,
++ * except that ep0_queue() is called in the main thread to acknowledge
++ * completion of various requests: set config, set interface, and
++ * Bulk-only device reset. */
++
++static void fsg_disconnect(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++
++ DBG(fsg, "disconnect or port reset\n");
++ raise_exception(fsg, FSG_STATE_DISCONNECT);
++}
++
++
++static int ep0_queue(struct fsg_dev *fsg)
++{
++ int rc;
++
++ rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC);
++ if (rc != 0 && rc != -ESHUTDOWN) {
++
++ /* We can't do much more than wait for a reset */
++ WARNING(fsg, "error in submission: %s --> %d\n",
++ fsg->ep0->name, rc);
++ }
++ return rc;
++}
++
++static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++
++ if (req->actual > 0)
++ dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
++ if (req->status || req->actual != req->length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual, req->length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ if (req->status == 0 && req->context)
++ ((fsg_routine_t) (req->context))(fsg);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Bulk and interrupt endpoint completion handlers.
++ * These always run in_irq. */
++
++static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_buffhd *bh = req->context;
++
++ if (req->status || req->actual != req->length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual, req->length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ /* Hold the lock while we update the request and buffer states */
++ smp_wmb();
++ spin_lock(&fsg->lock);
++ bh->inreq_busy = 0;
++ bh->state = BUF_STATE_EMPTY;
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_buffhd *bh = req->context;
++
++ dump_msg(fsg, "bulk-out", req->buf, req->actual);
++ if (req->status || req->actual != bh->bulk_out_intended_length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual,
++ bh->bulk_out_intended_length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ /* Hold the lock while we update the request and buffer states */
++ smp_wmb();
++ spin_lock(&fsg->lock);
++ bh->outreq_busy = 0;
++ bh->state = BUF_STATE_FULL;
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
++{
++ struct fsg_dev *fsg = ep->driver_data;
++ struct fsg_buffhd *bh = req->context;
++
++ if (req->status || req->actual != req->length)
++ DBG(fsg, "%s --> %d, %u/%u\n", __func__,
++ req->status, req->actual, req->length);
++ if (req->status == -ECONNRESET) // Request was cancelled
++ usb_ep_fifo_flush(ep);
++
++ /* Hold the lock while we update the request and buffer states */
++ smp_wmb();
++ spin_lock(&fsg->lock);
++ fsg->intreq_busy = 0;
++ bh->state = BUF_STATE_EMPTY;
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++#else
++static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
++{}
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Ep0 class-specific handlers. These always run in_irq. */
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct usb_request *req = fsg->ep0req;
++ static u8 cbi_reset_cmnd[6] = {
++ SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
++
++ /* Error in command transfer? */
++ if (req->status || req->length != req->actual ||
++ req->actual < 6 || req->actual > MAX_COMMAND_SIZE) {
++
++ /* Not all controllers allow a protocol stall after
++ * receiving control-out data, but we'll try anyway. */
++ fsg_set_halt(fsg, fsg->ep0);
++ return; // Wait for reset
++ }
++
++ /* Is it the special reset command? */
++ if (req->actual >= sizeof cbi_reset_cmnd &&
++ memcmp(req->buf, cbi_reset_cmnd,
++ sizeof cbi_reset_cmnd) == 0) {
++
++ /* Raise an exception to stop the current operation
++ * and reinitialize our state. */
++ DBG(fsg, "cbi reset request\n");
++ raise_exception(fsg, FSG_STATE_RESET);
++ return;
++ }
++
++ VDBG(fsg, "CB[I] accept device-specific command\n");
++ spin_lock(&fsg->lock);
++
++ /* Save the command for later */
++ if (fsg->cbbuf_cmnd_size)
++ WARNING(fsg, "CB[I] overwriting previous command\n");
++ fsg->cbbuf_cmnd_size = req->actual;
++ memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
++
++ wakeup_thread(fsg);
++ spin_unlock(&fsg->lock);
++}
++
++#else
++static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{}
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++
++static int class_setup_req(struct fsg_dev *fsg,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct usb_request *req = fsg->ep0req;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++ u16 w_length = le16_to_cpu(ctrl->wLength);
++
++ if (!fsg->config)
++ return value;
++
++ /* Handle Bulk-only class-specific requests */
++ if (transport_is_bbb()) {
++ switch (ctrl->bRequest) {
++
++ case US_BULK_RESET_REQUEST:
++ if (ctrl->bRequestType != (USB_DIR_OUT |
++ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++ break;
++ if (w_index != 0 || w_value != 0 || w_length != 0) {
++ value = -EDOM;
++ break;
++ }
++
++ /* Raise an exception to stop the current operation
++ * and reinitialize our state. */
++ DBG(fsg, "bulk reset request\n");
++ raise_exception(fsg, FSG_STATE_RESET);
++ value = DELAYED_STATUS;
++ break;
++
++ case US_BULK_GET_MAX_LUN:
++ if (ctrl->bRequestType != (USB_DIR_IN |
++ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++ break;
++ if (w_index != 0 || w_value != 0 || w_length != 1) {
++ value = -EDOM;
++ break;
++ }
++ VDBG(fsg, "get max LUN\n");
++ *(u8 *) req->buf = fsg->nluns - 1;
++ value = 1;
++ break;
++ }
++ }
++
++ /* Handle CBI class-specific requests */
++ else {
++ switch (ctrl->bRequest) {
++
++ case USB_CBI_ADSC_REQUEST:
++ if (ctrl->bRequestType != (USB_DIR_OUT |
++ USB_TYPE_CLASS | USB_RECIP_INTERFACE))
++ break;
++ if (w_index != 0 || w_value != 0) {
++ value = -EDOM;
++ break;
++ }
++ if (w_length > MAX_COMMAND_SIZE) {
++ value = -EOVERFLOW;
++ break;
++ }
++ value = w_length;
++ fsg->ep0req->context = received_cbi_adsc;
++ break;
++ }
++ }
++
++ if (value == -EOPNOTSUPP)
++ VDBG(fsg,
++ "unknown class-specific control req "
++ "%02x.%02x v%04x i%04x l%u\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ le16_to_cpu(ctrl->wValue), w_index, w_length);
++ return value;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Ep0 standard request handlers. These always run in_irq. */
++
++static int standard_setup_req(struct fsg_dev *fsg,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct usb_request *req = fsg->ep0req;
++ int value = -EOPNOTSUPP;
++ u16 w_index = le16_to_cpu(ctrl->wIndex);
++ u16 w_value = le16_to_cpu(ctrl->wValue);
++
++ /* Usually this just stores reply data in the pre-allocated ep0 buffer,
++ * but config change events will also reconfigure hardware. */
++ switch (ctrl->bRequest) {
++
++ case USB_REQ_GET_DESCRIPTOR:
++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++ USB_RECIP_DEVICE))
++ break;
++ switch (w_value >> 8) {
++
++ case USB_DT_DEVICE:
++ VDBG(fsg, "get device descriptor\n");
++ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
++ value = sizeof device_desc;
++ memcpy(req->buf, &device_desc, value);
++ break;
++ case USB_DT_DEVICE_QUALIFIER:
++ VDBG(fsg, "get device qualifier\n");
++ if (!gadget_is_dualspeed(fsg->gadget) ||
++ fsg->gadget->speed == USB_SPEED_SUPER)
++ break;
++ /*
++ * Assume ep0 uses the same maxpacket value for both
++ * speeds
++ */
++ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
++ value = sizeof dev_qualifier;
++ memcpy(req->buf, &dev_qualifier, value);
++ break;
++
++ case USB_DT_OTHER_SPEED_CONFIG:
++ VDBG(fsg, "get other-speed config descriptor\n");
++ if (!gadget_is_dualspeed(fsg->gadget) ||
++ fsg->gadget->speed == USB_SPEED_SUPER)
++ break;
++ goto get_config;
++ case USB_DT_CONFIG:
++ VDBG(fsg, "get configuration descriptor\n");
++get_config:
++ value = populate_config_buf(fsg->gadget,
++ req->buf,
++ w_value >> 8,
++ w_value & 0xff);
++ break;
++
++ case USB_DT_STRING:
++ VDBG(fsg, "get string descriptor\n");
++
++ /* wIndex == language code */
++ value = usb_gadget_get_string(&fsg_stringtab,
++ w_value & 0xff, req->buf);
++ break;
++
++ case USB_DT_BOS:
++ VDBG(fsg, "get bos descriptor\n");
++
++ if (gadget_is_superspeed(fsg->gadget))
++ value = populate_bos(fsg, req->buf);
++ break;
++ }
++
++ break;
++
++ /* One config, two speeds */
++ case USB_REQ_SET_CONFIGURATION:
++ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
++ USB_RECIP_DEVICE))
++ break;
++ VDBG(fsg, "set configuration\n");
++ if (w_value == CONFIG_VALUE || w_value == 0) {
++ fsg->new_config = w_value;
++
++ /* Raise an exception to wipe out previous transaction
++ * state (queued bufs, etc) and set the new config. */
++ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);
++ value = DELAYED_STATUS;
++ }
++ break;
++ case USB_REQ_GET_CONFIGURATION:
++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++ USB_RECIP_DEVICE))
++ break;
++ VDBG(fsg, "get configuration\n");
++ *(u8 *) req->buf = fsg->config;
++ value = 1;
++ break;
++
++ case USB_REQ_SET_INTERFACE:
++ if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |
++ USB_RECIP_INTERFACE))
++ break;
++ if (fsg->config && w_index == 0) {
++
++ /* Raise an exception to wipe out previous transaction
++ * state (queued bufs, etc) and install the new
++ * interface altsetting. */
++ raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);
++ value = DELAYED_STATUS;
++ }
++ break;
++ case USB_REQ_GET_INTERFACE:
++ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |
++ USB_RECIP_INTERFACE))
++ break;
++ if (!fsg->config)
++ break;
++ if (w_index != 0) {
++ value = -EDOM;
++ break;
++ }
++ VDBG(fsg, "get interface\n");
++ *(u8 *) req->buf = 0;
++ value = 1;
++ break;
++
++ default:
++ VDBG(fsg,
++ "unknown control req %02x.%02x v%04x i%04x l%u\n",
++ ctrl->bRequestType, ctrl->bRequest,
++ w_value, w_index, le16_to_cpu(ctrl->wLength));
++ }
++
++ return value;
++}
++
++
++static int fsg_setup(struct usb_gadget *gadget,
++ const struct usb_ctrlrequest *ctrl)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++ int rc;
++ int w_length = le16_to_cpu(ctrl->wLength);
++
++ ++fsg->ep0_req_tag; // Record arrival of a new request
++ fsg->ep0req->context = NULL;
++ fsg->ep0req->length = 0;
++ dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
++
++ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
++ rc = class_setup_req(fsg, ctrl);
++ else
++ rc = standard_setup_req(fsg, ctrl);
++
++ /* Respond with data/status or defer until later? */
++ if (rc >= 0 && rc != DELAYED_STATUS) {
++ rc = min(rc, w_length);
++ fsg->ep0req->length = rc;
++ fsg->ep0req->zero = rc < w_length;
++ fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
++ "ep0-in" : "ep0-out");
++ rc = ep0_queue(fsg);
++ }
++
++ /* Device either stalls (rc < 0) or reports success */
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* All the following routines run in process context */
++
++
++/* Use this for bulk or interrupt transfers, not ep0 */
++static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
++ struct usb_request *req, int *pbusy,
++ enum fsg_buffer_state *state)
++{
++ int rc;
++
++ if (ep == fsg->bulk_in)
++ dump_msg(fsg, "bulk-in", req->buf, req->length);
++ else if (ep == fsg->intr_in)
++ dump_msg(fsg, "intr-in", req->buf, req->length);
++
++ spin_lock_irq(&fsg->lock);
++ *pbusy = 1;
++ *state = BUF_STATE_BUSY;
++ spin_unlock_irq(&fsg->lock);
++ rc = usb_ep_queue(ep, req, GFP_KERNEL);
++ if (rc != 0) {
++ *pbusy = 0;
++ *state = BUF_STATE_EMPTY;
++
++ /* We can't do much more than wait for a reset */
++
++ /* Note: currently the net2280 driver fails zero-length
++ * submissions if DMA is enabled. */
++ if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&
++ req->length == 0))
++ WARNING(fsg, "error in submission: %s --> %d\n",
++ ep->name, rc);
++ }
++}
++
++
++static int sleep_thread(struct fsg_dev *fsg)
++{
++ int rc = 0;
++
++ /* Wait until a signal arrives or we are woken up */
++ for (;;) {
++ try_to_freeze();
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (signal_pending(current)) {
++ rc = -EINTR;
++ break;
++ }
++ if (fsg->thread_wakeup_needed)
++ break;
++ schedule();
++ }
++ __set_current_state(TASK_RUNNING);
++ fsg->thread_wakeup_needed = 0;
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_read(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba;
++ struct fsg_buffhd *bh;
++ int rc;
++ u32 amount_left;
++ loff_t file_offset, file_offset_tmp;
++ unsigned int amount;
++ ssize_t nread;
++
++ /* Get the starting Logical Block Address and check that it's
++ * not too big */
++ if (fsg->cmnd[0] == READ_6)
++ lba = get_unaligned_be24(&fsg->cmnd[1]);
++ else {
++ lba = get_unaligned_be32(&fsg->cmnd[2]);
++
++ /* We allow DPO (Disable Page Out = don't save data in the
++ * cache) and FUA (Force Unit Access = don't read from the
++ * cache), but we don't implement them. */
++ if ((fsg->cmnd[1] & ~0x18) != 0) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ }
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++ file_offset = ((loff_t) lba) << curlun->blkbits;
++
++ /* Carry out the file reads */
++ amount_left = fsg->data_size_from_cmnd;
++ if (unlikely(amount_left == 0))
++ return -EIO; // No default reply
++
++ for (;;) {
++
++ /* Figure out how much we need to read:
++ * Try to read the remaining amount.
++ * But don't read more than the buffer size.
++ * And don't try to read past the end of the file.
++ */
++ amount = min((unsigned int) amount_left, mod_data.buflen);
++ amount = min((loff_t) amount,
++ curlun->file_length - file_offset);
++
++ /* Wait for the next buffer to become available */
++ bh = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ /* If we were asked to read past the end of file,
++ * end with an empty buffer. */
++ if (amount == 0) {
++ curlun->sense_data =
++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ bh->inreq->length = 0;
++ bh->state = BUF_STATE_FULL;
++ break;
++ }
++
++ /* Perform the read */
++ file_offset_tmp = file_offset;
++ nread = vfs_read(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
++ (unsigned long long) file_offset,
++ (int) nread);
++ if (signal_pending(current))
++ return -EINTR;
++
++ if (nread < 0) {
++ LDBG(curlun, "error in file read: %d\n",
++ (int) nread);
++ nread = 0;
++ } else if (nread < amount) {
++ LDBG(curlun, "partial file read: %d/%u\n",
++ (int) nread, amount);
++ nread = round_down(nread, curlun->blksize);
++ }
++ file_offset += nread;
++ amount_left -= nread;
++ fsg->residue -= nread;
++++
++ /* Except at the end of the transfer, nread will be
++ * equal to the buffer size, which is divisible by the
++ * bulk-in maxpacket size.
++ */
++ bh->inreq->length = nread;
++ bh->state = BUF_STATE_FULL;
++++
++ /* If an error occurred, report it and its position */
++ if (nread < amount) {
++ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ if (amount_left == 0)
++ break; // No more left to read
++
++ /* Send this buffer and go read some more */
++ bh->inreq->zero = 0;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ }
++
++ return -EIO; // No default reply
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_write(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba;
++ struct fsg_buffhd *bh;
++ int get_some_more;
++ u32 amount_left_to_req, amount_left_to_write;
++ loff_t usb_offset, file_offset, file_offset_tmp;
++ unsigned int amount;
++ ssize_t nwritten;
++ int rc;
++
++ if (curlun->ro) {
++ curlun->sense_data = SS_WRITE_PROTECTED;
++ return -EINVAL;
++ }
++ spin_lock(&curlun->filp->f_lock);
++ curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait
++ spin_unlock(&curlun->filp->f_lock);
++
++ /* Get the starting Logical Block Address and check that it's
++ * not too big */
++ if (fsg->cmnd[0] == WRITE_6)
++ lba = get_unaligned_be24(&fsg->cmnd[1]);
++ else {
++ lba = get_unaligned_be32(&fsg->cmnd[2]);
++
++ /* We allow DPO (Disable Page Out = don't save data in the
++ * cache) and FUA (Force Unit Access = write directly to the
++ * medium). We don't implement DPO; we implement FUA by
++ * performing synchronous output. */
++ if ((fsg->cmnd[1] & ~0x18) != 0) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ /* FUA */
++ if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
++ spin_lock(&curlun->filp->f_lock);
++ curlun->filp->f_flags |= O_DSYNC;
++ spin_unlock(&curlun->filp->f_lock);
++ }
++ }
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++
++ /* Carry out the file writes */
++ get_some_more = 1;
++ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
++ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
++
++ while (amount_left_to_write > 0) {
++
++ /* Queue a request for more data from the host */
++ bh = fsg->next_buffhd_to_fill;
++ if (bh->state == BUF_STATE_EMPTY && get_some_more) {
++
++ /* Figure out how much we want to get:
++ * Try to get the remaining amount,
++ * but not more than the buffer size.
++ */
++ amount = min(amount_left_to_req, mod_data.buflen);
++
++ /* Beyond the end of the backing file? */
++ if (usb_offset >= curlun->file_length) {
++ get_some_more = 0;
++ curlun->sense_data =
++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ curlun->sense_data_info = usb_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ continue;
++ }
++
++ /* Get the next buffer */
++ usb_offset += amount;
++ fsg->usb_amount_left -= amount;
++ amount_left_to_req -= amount;
++ if (amount_left_to_req == 0)
++ get_some_more = 0;
++
++ /* Except at the end of the transfer, amount will be
++ * equal to the buffer size, which is divisible by
++ * the bulk-out maxpacket size.
++ */
++ set_bulk_out_req_length(fsg, bh, amount);
++ start_transfer(fsg, fsg->bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ continue;
++ }
++
++ /* Write the received data to the backing file */
++ bh = fsg->next_buffhd_to_drain;
++ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
++ break; // We stopped early
++ if (bh->state == BUF_STATE_FULL) {
++ smp_rmb();
++ fsg->next_buffhd_to_drain = bh->next;
++ bh->state = BUF_STATE_EMPTY;
++
++ /* Did something go wrong with the transfer? */
++ if (bh->outreq->status != 0) {
++ curlun->sense_data = SS_COMMUNICATION_FAILURE;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ amount = bh->outreq->actual;
++ if (curlun->file_length - file_offset < amount) {
++ LERROR(curlun,
++ "write %u @ %llu beyond end %llu\n",
++ amount, (unsigned long long) file_offset,
++ (unsigned long long) curlun->file_length);
++ amount = curlun->file_length - file_offset;
++ }
++
++ /* Don't accept excess data. The spec doesn't say
++ * what to do in this case. We'll ignore the error.
++ */
++ amount = min(amount, bh->bulk_out_intended_length);
++
++ /* Don't write a partial block */
++ amount = round_down(amount, curlun->blksize);
++ if (amount == 0)
++ goto empty_write;
++
++ /* Perform the write */
++ file_offset_tmp = file_offset;
++ nwritten = vfs_write(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
++ (unsigned long long) file_offset,
++ (int) nwritten);
++ if (signal_pending(current))
++ return -EINTR; // Interrupted!
++
++ if (nwritten < 0) {
++ LDBG(curlun, "error in file write: %d\n",
++ (int) nwritten);
++ nwritten = 0;
++ } else if (nwritten < amount) {
++ LDBG(curlun, "partial file write: %d/%u\n",
++ (int) nwritten, amount);
++ nwritten = round_down(nwritten, curlun->blksize);
++ }
++ file_offset += nwritten;
++ amount_left_to_write -= nwritten;
++ fsg->residue -= nwritten;
++
++ /* If an error occurred, report it and its position */
++ if (nwritten < amount) {
++ curlun->sense_data = SS_WRITE_ERROR;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ empty_write:
++ /* Did the host decide to stop early? */
++ if (bh->outreq->actual < bh->bulk_out_intended_length) {
++ fsg->short_packet_received = 1;
++ break;
++ }
++ continue;
++ }
++
++ /* Wait for something to happen */
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ return -EIO; // No default reply
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_synchronize_cache(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int rc;
++
++ /* We ignore the requested LBA and write out all file's
++ * dirty data buffers. */
++ rc = fsg_lun_fsync_sub(curlun);
++ if (rc)
++ curlun->sense_data = SS_WRITE_ERROR;
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static void invalidate_sub(struct fsg_lun *curlun)
++{
++ struct file *filp = curlun->filp;
++ struct inode *inode = filp->f_path.dentry->d_inode;
++ unsigned long rc;
++
++ rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
++ VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
++}
++
++static int do_verify(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba;
++ u32 verification_length;
++ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
++ loff_t file_offset, file_offset_tmp;
++ u32 amount_left;
++ unsigned int amount;
++ ssize_t nread;
++
++ /* Get the starting Logical Block Address and check that it's
++ * not too big */
++ lba = get_unaligned_be32(&fsg->cmnd[2]);
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++
++ /* We allow DPO (Disable Page Out = don't save data in the
++ * cache) but we don't implement it. */
++ if ((fsg->cmnd[1] & ~0x10) != 0) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ verification_length = get_unaligned_be16(&fsg->cmnd[7]);
++ if (unlikely(verification_length == 0))
++ return -EIO; // No default reply
++
++ /* Prepare to carry out the file verify */
++ amount_left = verification_length << curlun->blkbits;
++ file_offset = ((loff_t) lba) << curlun->blkbits;
++
++ /* Write out all the dirty buffers before invalidating them */
++ fsg_lun_fsync_sub(curlun);
++ if (signal_pending(current))
++ return -EINTR;
++
++ invalidate_sub(curlun);
++ if (signal_pending(current))
++ return -EINTR;
++
++ /* Just try to read the requested blocks */
++ while (amount_left > 0) {
++
++ /* Figure out how much we need to read:
++ * Try to read the remaining amount, but not more than
++ * the buffer size.
++ * And don't try to read past the end of the file.
++ */
++ amount = min((unsigned int) amount_left, mod_data.buflen);
++ amount = min((loff_t) amount,
++ curlun->file_length - file_offset);
++ if (amount == 0) {
++ curlun->sense_data =
++ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++
++ /* Perform the read */
++ file_offset_tmp = file_offset;
++ nread = vfs_read(curlun->filp,
++ (char __user *) bh->buf,
++ amount, &file_offset_tmp);
++ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
++ (unsigned long long) file_offset,
++ (int) nread);
++ if (signal_pending(current))
++ return -EINTR;
++
++ if (nread < 0) {
++ LDBG(curlun, "error in file verify: %d\n",
++ (int) nread);
++ nread = 0;
++ } else if (nread < amount) {
++ LDBG(curlun, "partial file verify: %d/%u\n",
++ (int) nread, amount);
++ nread = round_down(nread, curlun->blksize);
++ }
++ if (nread == 0) {
++ curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
++ curlun->sense_data_info = file_offset >> curlun->blkbits;
++ curlun->info_valid = 1;
++ break;
++ }
++ file_offset += nread;
++ amount_left -= nread;
++ }
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ u8 *buf = (u8 *) bh->buf;
++
++ static char vendor_id[] = "Linux ";
++ static char product_disk_id[] = "File-Stor Gadget";
++ static char product_cdrom_id[] = "File-CD Gadget ";
++
++ if (!fsg->curlun) { // Unsupported LUNs are okay
++ fsg->bad_lun_okay = 1;
++ memset(buf, 0, 36);
++ buf[0] = 0x7f; // Unsupported, no device-type
++ buf[4] = 31; // Additional length
++ return 36;
++ }
++
++ memset(buf, 0, 8);
++ buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
++ if (mod_data.removable)
++ buf[1] = 0x80;
++ buf[2] = 2; // ANSI SCSI level 2
++ buf[3] = 2; // SCSI-2 INQUIRY data format
++ buf[4] = 31; // Additional length
++ // No special options
++ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
++ (mod_data.cdrom ? product_cdrom_id :
++ product_disk_id),
++ mod_data.release);
++ return 36;
++}
++
++
++static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u8 *buf = (u8 *) bh->buf;
++ u32 sd, sdinfo;
++ int valid;
++
++ /*
++ * From the SCSI-2 spec., section 7.9 (Unit attention condition):
++ *
++ * If a REQUEST SENSE command is received from an initiator
++ * with a pending unit attention condition (before the target
++ * generates the contingent allegiance condition), then the
++ * target shall either:
++ * a) report any pending sense data and preserve the unit
++ * attention condition on the logical unit, or,
++ * b) report the unit attention condition, may discard any
++ * pending sense data, and clear the unit attention
++ * condition on the logical unit for that initiator.
++ *
++ * FSG normally uses option a); enable this code to use option b).
++ */
++#if 0
++ if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
++ curlun->sense_data = curlun->unit_attention_data;
++ curlun->unit_attention_data = SS_NO_SENSE;
++ }
++#endif
++
++ if (!curlun) { // Unsupported LUNs are okay
++ fsg->bad_lun_okay = 1;
++ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
++ sdinfo = 0;
++ valid = 0;
++ } else {
++ sd = curlun->sense_data;
++ sdinfo = curlun->sense_data_info;
++ valid = curlun->info_valid << 7;
++ curlun->sense_data = SS_NO_SENSE;
++ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
++ }
++
++ memset(buf, 0, 18);
++ buf[0] = valid | 0x70; // Valid, current error
++ buf[2] = SK(sd);
++ put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
++ buf[7] = 18 - 8; // Additional sense length
++ buf[12] = ASC(sd);
++ buf[13] = ASCQ(sd);
++ return 18;
++}
++
++
++static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
++ int pmi = fsg->cmnd[8];
++ u8 *buf = (u8 *) bh->buf;
++
++ /* Check the PMI and LBA fields */
++ if (pmi > 1 || (pmi == 0 && lba != 0)) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
++ /* Max logical block */
++ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
++ return 8;
++}
++
++
++static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int msf = fsg->cmnd[1] & 0x02;
++ u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
++ u8 *buf = (u8 *) bh->buf;
++
++ if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ if (lba >= curlun->num_sectors) {
++ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
++ return -EINVAL;
++ }
++
++ memset(buf, 0, 8);
++ buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
++ store_cdrom_address(&buf[4], msf, lba);
++ return 8;
++}
++
++
++static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int msf = fsg->cmnd[1] & 0x02;
++ int start_track = fsg->cmnd[6];
++ u8 *buf = (u8 *) bh->buf;
++
++ if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
++ start_track > 1) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ memset(buf, 0, 20);
++ buf[1] = (20-2); /* TOC data length */
++ buf[2] = 1; /* First track number */
++ buf[3] = 1; /* Last track number */
++ buf[5] = 0x16; /* Data track, copying allowed */
++ buf[6] = 0x01; /* Only track is number 1 */
++ store_cdrom_address(&buf[8], msf, 0);
++
++ buf[13] = 0x16; /* Lead-out track is data */
++ buf[14] = 0xAA; /* Lead-out track number */
++ store_cdrom_address(&buf[16], msf, curlun->num_sectors);
++ return 20;
++}
++
++
++static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int mscmnd = fsg->cmnd[0];
++ u8 *buf = (u8 *) bh->buf;
++ u8 *buf0 = buf;
++ int pc, page_code;
++ int changeable_values, all_pages;
++ int valid_page = 0;
++ int len, limit;
++
++ if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ pc = fsg->cmnd[2] >> 6;
++ page_code = fsg->cmnd[2] & 0x3f;
++ if (pc == 3) {
++ curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
++ return -EINVAL;
++ }
++ changeable_values = (pc == 1);
++ all_pages = (page_code == 0x3f);
++
++ /* Write the mode parameter header. Fixed values are: default
++ * medium type, no cache control (DPOFUA), and no block descriptors.
++ * The only variable value is the WriteProtect bit. We will fill in
++ * the mode data length later. */
++ memset(buf, 0, 8);
++ if (mscmnd == MODE_SENSE) {
++ buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
++ buf += 4;
++ limit = 255;
++ } else { // MODE_SENSE_10
++ buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
++ buf += 8;
++ limit = 65535; // Should really be mod_data.buflen
++ }
++
++ /* No block descriptors */
++
++ /* The mode pages, in numerical order. The only page we support
++ * is the Caching page. */
++ if (page_code == 0x08 || all_pages) {
++ valid_page = 1;
++ buf[0] = 0x08; // Page code
++ buf[1] = 10; // Page length
++ memset(buf+2, 0, 10); // None of the fields are changeable
++
++ if (!changeable_values) {
++ buf[2] = 0x04; // Write cache enable,
++ // Read cache not disabled
++ // No cache retention priorities
++ put_unaligned_be16(0xffff, &buf[4]);
++ /* Don't disable prefetch */
++ /* Minimum prefetch = 0 */
++ put_unaligned_be16(0xffff, &buf[8]);
++ /* Maximum prefetch */
++ put_unaligned_be16(0xffff, &buf[10]);
++ /* Maximum prefetch ceiling */
++ }
++ buf += 12;
++ }
++
++ /* Check that a valid page was requested and the mode data length
++ * isn't too long. */
++ len = buf - buf0;
++ if (!valid_page || len > limit) {
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ /* Store the mode data length */
++ if (mscmnd == MODE_SENSE)
++ buf0[0] = len - 1;
++ else
++ put_unaligned_be16(len - 2, buf0);
++ return len;
++}
++
++
++static int do_start_stop(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int loej, start;
++
++ if (!mod_data.removable) {
++ curlun->sense_data = SS_INVALID_COMMAND;
++ return -EINVAL;
++ }
++
++ // int immed = fsg->cmnd[1] & 0x01;
++ loej = fsg->cmnd[4] & 0x02;
++ start = fsg->cmnd[4] & 0x01;
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++ if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed
++ (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ if (!start) {
++
++ /* Are we allowed to unload the media? */
++ if (curlun->prevent_medium_removal) {
++ LDBG(curlun, "unload attempt prevented\n");
++ curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
++ return -EINVAL;
++ }
++ if (loej) { // Simulate an unload/eject
++ up_read(&fsg->filesem);
++ down_write(&fsg->filesem);
++ fsg_lun_close(curlun);
++ up_write(&fsg->filesem);
++ down_read(&fsg->filesem);
++ }
++ } else {
++
++ /* Our emulation doesn't support mounting; the medium is
++ * available for use as soon as it is loaded. */
++ if (!fsg_lun_is_open(curlun)) {
++ curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
++ return -EINVAL;
++ }
++ }
++#endif
++ return 0;
++}
++
++
++static int do_prevent_allow(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ int prevent;
++
++ if (!mod_data.removable) {
++ curlun->sense_data = SS_INVALID_COMMAND;
++ return -EINVAL;
++ }
++
++ prevent = fsg->cmnd[4] & 0x01;
++ if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++
++ if (curlun->prevent_medium_removal && !prevent)
++ fsg_lun_fsync_sub(curlun);
++ curlun->prevent_medium_removal = prevent;
++ return 0;
++}
++
++
++static int do_read_format_capacities(struct fsg_dev *fsg,
++ struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ u8 *buf = (u8 *) bh->buf;
++
++ buf[0] = buf[1] = buf[2] = 0;
++ buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
++ buf += 4;
++
++ put_unaligned_be32(curlun->num_sectors, &buf[0]);
++ /* Number of blocks */
++ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
++ buf[4] = 0x02; /* Current capacity */
++ return 12;
++}
++
++
++static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++
++ /* We don't support MODE SELECT */
++ curlun->sense_data = SS_INVALID_COMMAND;
++ return -EINVAL;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
++{
++ int rc;
++
++ rc = fsg_set_halt(fsg, fsg->bulk_in);
++ if (rc == -EAGAIN)
++ VDBG(fsg, "delayed bulk-in endpoint halt\n");
++ while (rc != 0) {
++ if (rc != -EAGAIN) {
++ WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
++ rc = 0;
++ break;
++ }
++
++ /* Wait for a short time and then try again */
++ if (msleep_interruptible(100) != 0)
++ return -EINTR;
++ rc = usb_ep_set_halt(fsg->bulk_in);
++ }
++ return rc;
++}
++
++static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
++{
++ int rc;
++
++ DBG(fsg, "bulk-in set wedge\n");
++ rc = usb_ep_set_wedge(fsg->bulk_in);
++ if (rc == -EAGAIN)
++ VDBG(fsg, "delayed bulk-in endpoint wedge\n");
++ while (rc != 0) {
++ if (rc != -EAGAIN) {
++ WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
++ rc = 0;
++ break;
++ }
++
++ /* Wait for a short time and then try again */
++ if (msleep_interruptible(100) != 0)
++ return -EINTR;
++ rc = usb_ep_set_wedge(fsg->bulk_in);
++ }
++ return rc;
++}
++
++static int throw_away_data(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh;
++ u32 amount;
++ int rc;
++
++ while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY ||
++ fsg->usb_amount_left > 0) {
++
++ /* Throw away the data in a filled buffer */
++ if (bh->state == BUF_STATE_FULL) {
++ smp_rmb();
++ bh->state = BUF_STATE_EMPTY;
++ fsg->next_buffhd_to_drain = bh->next;
++
++ /* A short packet or an error ends everything */
++ if (bh->outreq->actual < bh->bulk_out_intended_length ||
++ bh->outreq->status != 0) {
++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ return -EINTR;
++ }
++ continue;
++ }
++
++ /* Try to submit another request if we need one */
++ bh = fsg->next_buffhd_to_fill;
++ if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
++ amount = min(fsg->usb_amount_left,
++ (u32) mod_data.buflen);
++
++ /* Except at the end of the transfer, amount will be
++ * equal to the buffer size, which is divisible by
++ * the bulk-out maxpacket size.
++ */
++ set_bulk_out_req_length(fsg, bh, amount);
++ start_transfer(fsg, fsg->bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ fsg->usb_amount_left -= amount;
++ continue;
++ }
++
++ /* Otherwise wait for something to happen */
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++ return 0;
++}
++
++
++static int finish_reply(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
++ int rc = 0;
++
++ switch (fsg->data_dir) {
++ case DATA_DIR_NONE:
++ break; // Nothing to send
++
++ /* If we don't know whether the host wants to read or write,
++ * this must be CB or CBI with an unknown command. We mustn't
++ * try to send or receive any data. So stall both bulk pipes
++ * if we can and wait for a reset. */
++ case DATA_DIR_UNKNOWN:
++ if (mod_data.can_stall) {
++ fsg_set_halt(fsg, fsg->bulk_out);
++ rc = halt_bulk_in_endpoint(fsg);
++ }
++ break;
++
++ /* All but the last buffer of data must have already been sent */
++ case DATA_DIR_TO_HOST:
++ if (fsg->data_size == 0)
++ ; // Nothing to send
++
++ /* If there's no residue, simply send the last buffer */
++ else if (fsg->residue == 0) {
++ bh->inreq->zero = 0;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ }
++
++ /* There is a residue. For CB and CBI, simply mark the end
++ * of the data with a short packet. However, if we are
++ * allowed to stall, there was no data at all (residue ==
++ * data_size), and the command failed (invalid LUN or
++ * sense data is set), then halt the bulk-in endpoint
++ * instead. */
++ else if (!transport_is_bbb()) {
++ if (mod_data.can_stall &&
++ fsg->residue == fsg->data_size &&
++ (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) {
++ bh->state = BUF_STATE_EMPTY;
++ rc = halt_bulk_in_endpoint(fsg);
++ } else {
++ bh->inreq->zero = 1;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ }
++ }
++
++ /*
++ * For Bulk-only, mark the end of the data with a short
++ * packet. If we are allowed to stall, halt the bulk-in
++ * endpoint. (Note: This violates the Bulk-Only Transport
++ * specification, which requires us to pad the data if we
++ * don't halt the endpoint. Presumably nobody will mind.)
++ */
++ else {
++ bh->inreq->zero = 1;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++ fsg->next_buffhd_to_fill = bh->next;
++ if (mod_data.can_stall)
++ rc = halt_bulk_in_endpoint(fsg);
++ }
++ break;
++
++ /* We have processed all we want from the data the host has sent.
++ * There may still be outstanding bulk-out requests. */
++ case DATA_DIR_FROM_HOST:
++ if (fsg->residue == 0)
++ ; // Nothing to receive
++
++ /* Did the host stop sending unexpectedly early? */
++ else if (fsg->short_packet_received) {
++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ rc = -EINTR;
++ }
++
++ /* We haven't processed all the incoming data. Even though
++ * we may be allowed to stall, doing so would cause a race.
++ * The controller may already have ACK'ed all the remaining
++ * bulk-out packets, in which case the host wouldn't see a
++ * STALL. Not realizing the endpoint was halted, it wouldn't
++ * clear the halt -- leading to problems later on. */
++#if 0
++ else if (mod_data.can_stall) {
++ fsg_set_halt(fsg, fsg->bulk_out);
++ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
++ rc = -EINTR;
++ }
++#endif
++
++ /* We can't stall. Read in the excess data and throw it
++ * all away. */
++ else
++ rc = throw_away_data(fsg);
++ break;
++ }
++ return rc;
++}
++
++
++static int send_status(struct fsg_dev *fsg)
++{
++ struct fsg_lun *curlun = fsg->curlun;
++ struct fsg_buffhd *bh;
++ int rc;
++ u8 status = US_BULK_STAT_OK;
++ u32 sd, sdinfo = 0;
++
++ /* Wait for the next buffer to become available */
++ bh = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ if (curlun) {
++ sd = curlun->sense_data;
++ sdinfo = curlun->sense_data_info;
++ } else if (fsg->bad_lun_okay)
++ sd = SS_NO_SENSE;
++ else
++ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
++
++ if (fsg->phase_error) {
++ DBG(fsg, "sending phase-error status\n");
++ status = US_BULK_STAT_PHASE;
++ sd = SS_INVALID_COMMAND;
++ } else if (sd != SS_NO_SENSE) {
++ DBG(fsg, "sending command-failure status\n");
++ status = US_BULK_STAT_FAIL;
++ VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
++ " info x%x\n",
++ SK(sd), ASC(sd), ASCQ(sd), sdinfo);
++ }
++
++ if (transport_is_bbb()) {
++ struct bulk_cs_wrap *csw = bh->buf;
++
++ /* Store and send the Bulk-only CSW */
++ csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
++ csw->Tag = fsg->tag;
++ csw->Residue = cpu_to_le32(fsg->residue);
++ csw->Status = status;
++
++ bh->inreq->length = US_BULK_CS_WRAP_LEN;
++ bh->inreq->zero = 0;
++ start_transfer(fsg, fsg->bulk_in, bh->inreq,
++ &bh->inreq_busy, &bh->state);
++
++ } else if (mod_data.transport_type == USB_PR_CB) {
++
++ /* Control-Bulk transport has no status phase! */
++ return 0;
++
++ } else { // USB_PR_CBI
++ struct interrupt_data *buf = bh->buf;
++
++ /* Store and send the Interrupt data. UFI sends the ASC
++ * and ASCQ bytes. Everything else sends a Type (which
++ * is always 0) and the status Value. */
++ if (mod_data.protocol_type == USB_SC_UFI) {
++ buf->bType = ASC(sd);
++ buf->bValue = ASCQ(sd);
++ } else {
++ buf->bType = 0;
++ buf->bValue = status;
++ }
++ fsg->intreq->length = CBI_INTERRUPT_DATA_LEN;
++
++ fsg->intr_buffhd = bh; // Point to the right buffhd
++ fsg->intreq->buf = bh->inreq->buf;
++ fsg->intreq->context = bh;
++ start_transfer(fsg, fsg->intr_in, fsg->intreq,
++ &fsg->intreq_busy, &bh->state);
++ }
++
++ fsg->next_buffhd_to_fill = bh->next;
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Check whether the command is properly formed and whether its data size
++ * and direction agree with the values we already have. */
++static int check_command(struct fsg_dev *fsg, int cmnd_size,
++ enum data_direction data_dir, unsigned int mask,
++ int needs_medium, const char *name)
++{
++ int i;
++ int lun = fsg->cmnd[1] >> 5;
++ static const char dirletter[4] = {'u', 'o', 'i', 'n'};
++ char hdlen[20];
++ struct fsg_lun *curlun;
++
++ /* Adjust the expected cmnd_size for protocol encapsulation padding.
++ * Transparent SCSI doesn't pad. */
++ if (protocol_is_scsi())
++ ;
++
++ /* There's some disagreement as to whether RBC pads commands or not.
++ * We'll play it safe and accept either form. */
++ else if (mod_data.protocol_type == USB_SC_RBC) {
++ if (fsg->cmnd_size == 12)
++ cmnd_size = 12;
++
++ /* All the other protocols pad to 12 bytes */
++ } else
++ cmnd_size = 12;
++
++ hdlen[0] = 0;
++ if (fsg->data_dir != DATA_DIR_UNKNOWN)
++ sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir],
++ fsg->data_size);
++ VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
++ name, cmnd_size, dirletter[(int) data_dir],
++ fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen);
++
++ /* We can't reply at all until we know the correct data direction
++ * and size. */
++ if (fsg->data_size_from_cmnd == 0)
++ data_dir = DATA_DIR_NONE;
++ if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI
++ fsg->data_dir = data_dir;
++ fsg->data_size = fsg->data_size_from_cmnd;
++
++ } else { // Bulk-only
++ if (fsg->data_size < fsg->data_size_from_cmnd) {
++
++ /* Host data size < Device data size is a phase error.
++ * Carry out the command, but only transfer as much
++ * as we are allowed. */
++ fsg->data_size_from_cmnd = fsg->data_size;
++ fsg->phase_error = 1;
++ }
++ }
++ fsg->residue = fsg->usb_amount_left = fsg->data_size;
++
++ /* Conflicting data directions is a phase error */
++ if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) {
++ fsg->phase_error = 1;
++ return -EINVAL;
++ }
++
++ /* Verify the length of the command itself */
++ if (cmnd_size != fsg->cmnd_size) {
++
++ /* Special case workaround: There are plenty of buggy SCSI
++ * implementations. Many have issues with cbw->Length
++ * field passing a wrong command size. For those cases we
++ * always try to work around the problem by using the length
++ * sent by the host side provided it is at least as large
++ * as the correct command length.
++ * Examples of such cases would be MS-Windows, which issues
++ * REQUEST SENSE with cbw->Length == 12 where it should
++ * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
++ * REQUEST SENSE with cbw->Length == 10 where it should
++ * be 6 as well.
++ */
++ if (cmnd_size <= fsg->cmnd_size) {
++ DBG(fsg, "%s is buggy! Expected length %d "
++ "but we got %d\n", name,
++ cmnd_size, fsg->cmnd_size);
++ cmnd_size = fsg->cmnd_size;
++ } else {
++ fsg->phase_error = 1;
++ return -EINVAL;
++ }
++ }
++
++ /* Check that the LUN values are consistent */
++ if (transport_is_bbb()) {
++ if (fsg->lun != lun)
++ DBG(fsg, "using LUN %d from CBW, "
++ "not LUN %d from CDB\n",
++ fsg->lun, lun);
++ }
++
++ /* Check the LUN */
++ curlun = fsg->curlun;
++ if (curlun) {
++ if (fsg->cmnd[0] != REQUEST_SENSE) {
++ curlun->sense_data = SS_NO_SENSE;
++ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
++ }
++ } else {
++ fsg->bad_lun_okay = 0;
++
++ /* INQUIRY and REQUEST SENSE commands are explicitly allowed
++ * to use unsupported LUNs; all others may not. */
++ if (fsg->cmnd[0] != INQUIRY &&
++ fsg->cmnd[0] != REQUEST_SENSE) {
++ DBG(fsg, "unsupported LUN %d\n", fsg->lun);
++ return -EINVAL;
++ }
++ }
++
++ /* If a unit attention condition exists, only INQUIRY and
++ * REQUEST SENSE commands are allowed; anything else must fail. */
++ if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
++ fsg->cmnd[0] != INQUIRY &&
++ fsg->cmnd[0] != REQUEST_SENSE) {
++ curlun->sense_data = curlun->unit_attention_data;
++ curlun->unit_attention_data = SS_NO_SENSE;
++ return -EINVAL;
++ }
++
++ /* Check that only command bytes listed in the mask are non-zero */
++ fsg->cmnd[1] &= 0x1f; // Mask away the LUN
++ for (i = 1; i < cmnd_size; ++i) {
++ if (fsg->cmnd[i] && !(mask & (1 << i))) {
++ if (curlun)
++ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
++ return -EINVAL;
++ }
++ }
++
++ /* If the medium isn't mounted and the command needs to access
++ * it, return an error. */
++ if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
++ curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/* wrapper of check_command for data size in blocks handling */
++static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
++ enum data_direction data_dir, unsigned int mask,
++ int needs_medium, const char *name)
++{
++ if (fsg->curlun)
++ fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
++ return check_command(fsg, cmnd_size, data_dir,
++ mask, needs_medium, name);
++}
++
++static int do_scsi_command(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh;
++ int rc;
++ int reply = -EINVAL;
++ int i;
++ static char unknown[16];
++
++ dump_cdb(fsg);
++
++ /* Wait for the next buffer to become available for data or status */
++ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++ fsg->phase_error = 0;
++ fsg->short_packet_received = 0;
++
++ down_read(&fsg->filesem); // We're using the backing file
++ switch (fsg->cmnd[0]) {
++
++ case INQUIRY:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<4), 0,
++ "INQUIRY")) == 0)
++ reply = do_inquiry(fsg, bh);
++ break;
++
++ case MODE_SELECT:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
++ (1<<1) | (1<<4), 0,
++ "MODE SELECT(6)")) == 0)
++ reply = do_mode_select(fsg, bh);
++ break;
++
++ case MODE_SELECT_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
++ (1<<1) | (3<<7), 0,
++ "MODE SELECT(10)")) == 0)
++ reply = do_mode_select(fsg, bh);
++ break;
++
++ case MODE_SENSE:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<1) | (1<<2) | (1<<4), 0,
++ "MODE SENSE(6)")) == 0)
++ reply = do_mode_sense(fsg, bh);
++ break;
++
++ case MODE_SENSE_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (1<<1) | (1<<2) | (3<<7), 0,
++ "MODE SENSE(10)")) == 0)
++ reply = do_mode_sense(fsg, bh);
++ break;
++
++ case ALLOW_MEDIUM_REMOVAL:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
++ (1<<4), 0,
++ "PREVENT-ALLOW MEDIUM REMOVAL")) == 0)
++ reply = do_prevent_allow(fsg);
++ break;
++
++ case READ_6:
++ i = fsg->cmnd[4];
++ fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
++ if ((reply = check_command_size_in_blocks(fsg, 6,
++ DATA_DIR_TO_HOST,
++ (7<<1) | (1<<4), 1,
++ "READ(6)")) == 0)
++ reply = do_read(fsg);
++ break;
++
++ case READ_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command_size_in_blocks(fsg, 10,
++ DATA_DIR_TO_HOST,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "READ(10)")) == 0)
++ reply = do_read(fsg);
++ break;
++
++ case READ_12:
++ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
++ if ((reply = check_command_size_in_blocks(fsg, 12,
++ DATA_DIR_TO_HOST,
++ (1<<1) | (0xf<<2) | (0xf<<6), 1,
++ "READ(12)")) == 0)
++ reply = do_read(fsg);
++ break;
++
++ case READ_CAPACITY:
++ fsg->data_size_from_cmnd = 8;
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (0xf<<2) | (1<<8), 1,
++ "READ CAPACITY")) == 0)
++ reply = do_read_capacity(fsg, bh);
++ break;
++
++ case READ_HEADER:
++ if (!mod_data.cdrom)
++ goto unknown_cmnd;
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (3<<7) | (0x1f<<1), 1,
++ "READ HEADER")) == 0)
++ reply = do_read_header(fsg, bh);
++ break;
++
++ case READ_TOC:
++ if (!mod_data.cdrom)
++ goto unknown_cmnd;
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (7<<6) | (1<<1), 1,
++ "READ TOC")) == 0)
++ reply = do_read_toc(fsg, bh);
++ break;
++
++ case READ_FORMAT_CAPACITIES:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
++ (3<<7), 1,
++ "READ FORMAT CAPACITIES")) == 0)
++ reply = do_read_format_capacities(fsg, bh);
++ break;
++
++ case REQUEST_SENSE:
++ fsg->data_size_from_cmnd = fsg->cmnd[4];
++ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
++ (1<<4), 0,
++ "REQUEST SENSE")) == 0)
++ reply = do_request_sense(fsg, bh);
++ break;
++
++ case START_STOP:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
++ (1<<1) | (1<<4), 0,
++ "START-STOP UNIT")) == 0)
++ reply = do_start_stop(fsg);
++ break;
++
++ case SYNCHRONIZE_CACHE:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
++ (0xf<<2) | (3<<7), 1,
++ "SYNCHRONIZE CACHE")) == 0)
++ reply = do_synchronize_cache(fsg);
++ break;
++
++ case TEST_UNIT_READY:
++ fsg->data_size_from_cmnd = 0;
++ reply = check_command(fsg, 6, DATA_DIR_NONE,
++ 0, 1,
++ "TEST UNIT READY");
++ break;
++++
++ /* Although optional, this command is used by MS-Windows. We
++ * support a minimal version: BytChk must be 0. */
++ case VERIFY:
++ fsg->data_size_from_cmnd = 0;
++ if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "VERIFY")) == 0)
++ reply = do_verify(fsg);
++ break;
++
++ case WRITE_6:
++ i = fsg->cmnd[4];
++ fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
++ if ((reply = check_command_size_in_blocks(fsg, 6,
++ DATA_DIR_FROM_HOST,
++ (7<<1) | (1<<4), 1,
++ "WRITE(6)")) == 0)
++ reply = do_write(fsg);
++ break;
++
++ case WRITE_10:
++ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
++ if ((reply = check_command_size_in_blocks(fsg, 10,
++ DATA_DIR_FROM_HOST,
++ (1<<1) | (0xf<<2) | (3<<7), 1,
++ "WRITE(10)")) == 0)
++ reply = do_write(fsg);
++ break;
++
++ case WRITE_12:
++ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
++ if ((reply = check_command_size_in_blocks(fsg, 12,
++ DATA_DIR_FROM_HOST,
++ (1<<1) | (0xf<<2) | (0xf<<6), 1,
++ "WRITE(12)")) == 0)
++ reply = do_write(fsg);
++ break;
++
++ /* Some mandatory commands that we recognize but don't implement.
++ * They don't mean much in this setting. It's left as an exercise
++ * for anyone interested to implement RESERVE and RELEASE in terms
++ * of Posix locks. */
++ case FORMAT_UNIT:
++ case RELEASE:
++ case RESERVE:
++ case SEND_DIAGNOSTIC:
++ // Fall through
++
++ default:
++ unknown_cmnd:
++ fsg->data_size_from_cmnd = 0;
++ sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
++ if ((reply = check_command(fsg, fsg->cmnd_size,
++ DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) {
++ fsg->curlun->sense_data = SS_INVALID_COMMAND;
++ reply = -EINVAL;
++ }
++ break;
++ }
++ up_read(&fsg->filesem);
++
++ if (reply == -EINTR || signal_pending(current))
++ return -EINTR;
++
++ /* Set up the single reply buffer for finish_reply() */
++ if (reply == -EINVAL)
++ reply = 0; // Error reply length
++ if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
++ reply = min((u32) reply, fsg->data_size_from_cmnd);
++ bh->inreq->length = reply;
++ bh->state = BUF_STATE_FULL;
++ fsg->residue -= reply;
++ } // Otherwise it's already set
++
++ return 0;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
++{
++ struct usb_request *req = bh->outreq;
++ struct bulk_cb_wrap *cbw = req->buf;
++
++ /* Was this a real packet? Should it be ignored? */
++ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
++ return -EINVAL;
++
++ /* Is the CBW valid? */
++ if (req->actual != US_BULK_CB_WRAP_LEN ||
++ cbw->Signature != cpu_to_le32(
++ US_BULK_CB_SIGN)) {
++ DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
++ req->actual,
++ le32_to_cpu(cbw->Signature));
++
++ /* The Bulk-only spec says we MUST stall the IN endpoint
++ * (6.6.1), so it's unavoidable. It also says we must
++ * retain this state until the next reset, but there's
++ * no way to tell the controller driver it should ignore
++ * Clear-Feature(HALT) requests.
++ *
++ * We aren't required to halt the OUT endpoint; instead
++ * we can simply accept and discard any data received
++ * until the next reset. */
++ wedge_bulk_in_endpoint(fsg);
++ set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
++ return -EINVAL;
++ }
++
++ /* Is the CBW meaningful? */
++ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
++ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
++ DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
++ "cmdlen %u\n",
++ cbw->Lun, cbw->Flags, cbw->Length);
++
++ /* We can do anything we want here, so let's stall the
++ * bulk pipes if we are allowed to. */
++ if (mod_data.can_stall) {
++ fsg_set_halt(fsg, fsg->bulk_out);
++ halt_bulk_in_endpoint(fsg);
++ }
++ return -EINVAL;
++ }
++
++ /* Save the command for later */
++ fsg->cmnd_size = cbw->Length;
++ memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
++ if (cbw->Flags & US_BULK_FLAG_IN)
++ fsg->data_dir = DATA_DIR_TO_HOST;
++ else
++ fsg->data_dir = DATA_DIR_FROM_HOST;
++ fsg->data_size = le32_to_cpu(cbw->DataTransferLength);
++ if (fsg->data_size == 0)
++ fsg->data_dir = DATA_DIR_NONE;
++ fsg->lun = cbw->Lun;
++ fsg->tag = cbw->Tag;
++ return 0;
++}
++
++
++static int get_next_command(struct fsg_dev *fsg)
++{
++ struct fsg_buffhd *bh;
++ int rc = 0;
++
++ if (transport_is_bbb()) {
++
++ /* Wait for the next buffer to become available */
++ bh = fsg->next_buffhd_to_fill;
++ while (bh->state != BUF_STATE_EMPTY) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ /* Queue a request to read a Bulk-only CBW */
++ set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
++ start_transfer(fsg, fsg->bulk_out, bh->outreq,
++ &bh->outreq_busy, &bh->state);
++
++ /* We will drain the buffer in software, which means we
++ * can reuse it for the next filling. No need to advance
++ * next_buffhd_to_fill. */
++
++ /* Wait for the CBW to arrive */
++ while (bh->state != BUF_STATE_FULL) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++ smp_rmb();
++ rc = received_cbw(fsg, bh);
++ bh->state = BUF_STATE_EMPTY;
++
++ } else { // USB_PR_CB or USB_PR_CBI
++
++ /* Wait for the next command to arrive */
++ while (fsg->cbbuf_cmnd_size == 0) {
++ rc = sleep_thread(fsg);
++ if (rc)
++ return rc;
++ }
++
++ /* Is the previous status interrupt request still busy?
++ * The host is allowed to skip reading the status,
++ * so we must cancel it. */
++ if (fsg->intreq_busy)
++ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
++
++ /* Copy the command and mark the buffer empty */
++ fsg->data_dir = DATA_DIR_UNKNOWN;
++ spin_lock_irq(&fsg->lock);
++ fsg->cmnd_size = fsg->cbbuf_cmnd_size;
++ memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
++ fsg->cbbuf_cmnd_size = 0;
++ spin_unlock_irq(&fsg->lock);
++
++ /* Use LUN from the command */
++ fsg->lun = fsg->cmnd[1] >> 5;
++ }
++
++ /* Update current lun */
++ if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
++ fsg->curlun = &fsg->luns[fsg->lun];
++ else
++ fsg->curlun = NULL;
++
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
++ const struct usb_endpoint_descriptor *d)
++{
++ int rc;
++
++ ep->driver_data = fsg;
++ ep->desc = d;
++ rc = usb_ep_enable(ep);
++ if (rc)
++ ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
++ return rc;
++}
++
++static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep,
++ struct usb_request **preq)
++{
++ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
++ if (*preq)
++ return 0;
++ ERROR(fsg, "can't allocate request for %s\n", ep->name);
++ return -ENOMEM;
++}
++
++/*
++ * Reset interface setting and re-init endpoint state (toggle etc).
++ * Call with altsetting < 0 to disable the interface. The only other
++ * available altsetting is 0, which enables the interface.
++ */
++static int do_set_interface(struct fsg_dev *fsg, int altsetting)
++{
++ int rc = 0;
++ int i;
++ const struct usb_endpoint_descriptor *d;
++
++ if (fsg->running)
++ DBG(fsg, "reset interface\n");
++
++reset:
++ /* Deallocate the requests */
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ struct fsg_buffhd *bh = &fsg->buffhds[i];
++
++ if (bh->inreq) {
++ usb_ep_free_request(fsg->bulk_in, bh->inreq);
++ bh->inreq = NULL;
++ }
++ if (bh->outreq) {
++ usb_ep_free_request(fsg->bulk_out, bh->outreq);
++ bh->outreq = NULL;
++ }
++ }
++ if (fsg->intreq) {
++ usb_ep_free_request(fsg->intr_in, fsg->intreq);
++ fsg->intreq = NULL;
++ }
++
++ /* Disable the endpoints */
++ if (fsg->bulk_in_enabled) {
++ usb_ep_disable(fsg->bulk_in);
++ fsg->bulk_in_enabled = 0;
++ }
++ if (fsg->bulk_out_enabled) {
++ usb_ep_disable(fsg->bulk_out);
++ fsg->bulk_out_enabled = 0;
++ }
++ if (fsg->intr_in_enabled) {
++ usb_ep_disable(fsg->intr_in);
++ fsg->intr_in_enabled = 0;
++ }
++
++ fsg->running = 0;
++ if (altsetting < 0 || rc != 0)
++ return rc;
++
++ DBG(fsg, "set interface %d\n", altsetting);
++
++ /* Enable the endpoints */
++ d = fsg_ep_desc(fsg->gadget,
++ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
++ &fsg_ss_bulk_in_desc);
++ if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
++ goto reset;
++ fsg->bulk_in_enabled = 1;
++
++ d = fsg_ep_desc(fsg->gadget,
++ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
++ &fsg_ss_bulk_out_desc);
++ if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
++ goto reset;
++ fsg->bulk_out_enabled = 1;
++ fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
++ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
++
++ if (transport_is_cbi()) {
++ d = fsg_ep_desc(fsg->gadget,
++ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
++ &fsg_ss_intr_in_desc);
++ if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
++ goto reset;
++ fsg->intr_in_enabled = 1;
++ }
++
++ /* Allocate the requests */
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ struct fsg_buffhd *bh = &fsg->buffhds[i];
++
++ if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
++ goto reset;
++ if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
++ goto reset;
++ bh->inreq->buf = bh->outreq->buf = bh->buf;
++ bh->inreq->context = bh->outreq->context = bh;
++ bh->inreq->complete = bulk_in_complete;
++ bh->outreq->complete = bulk_out_complete;
++ }
++ if (transport_is_cbi()) {
++ if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0)
++ goto reset;
++ fsg->intreq->complete = intr_in_complete;
++ }
++
++ fsg->running = 1;
++ for (i = 0; i < fsg->nluns; ++i)
++ fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
++ return rc;
++}
++
++
++/*
++ * Change our operational configuration. This code must agree with the code
++ * that returns config descriptors, and with interface altsetting code.
++ *
++ * It's also responsible for power management interactions. Some
++ * configurations might not work with our current power sources.
++ * For now we just assume the gadget is always self-powered.
++ */
++static int do_set_config(struct fsg_dev *fsg, u8 new_config)
++{
++ int rc = 0;
++
++ /* Disable the single interface */
++ if (fsg->config != 0) {
++ DBG(fsg, "reset config\n");
++ fsg->config = 0;
++ rc = do_set_interface(fsg, -1);
++ }
++
++ /* Enable the interface */
++ if (new_config != 0) {
++ fsg->config = new_config;
++ if ((rc = do_set_interface(fsg, 0)) != 0)
++ fsg->config = 0; // Reset on errors
++ else
++ INFO(fsg, "%s config #%d\n",
++ usb_speed_string(fsg->gadget->speed),
++ fsg->config);
++ }
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static void handle_exception(struct fsg_dev *fsg)
++{
++ siginfo_t info;
++ int sig;
++ int i;
++ int num_active;
++ struct fsg_buffhd *bh;
++ enum fsg_state old_state;
++ u8 new_config;
++ struct fsg_lun *curlun;
++ unsigned int exception_req_tag;
++ int rc;
++
++ /* Clear the existing signals. Anything but SIGUSR1 is converted
++ * into a high-priority EXIT exception. */
++ for (;;) {
++ sig = dequeue_signal_lock(current, &current->blocked, &info);
++ if (!sig)
++ break;
++ if (sig != SIGUSR1) {
++ if (fsg->state < FSG_STATE_EXIT)
++ DBG(fsg, "Main thread exiting on signal\n");
++ raise_exception(fsg, FSG_STATE_EXIT);
++ }
++ }
++
++ /* Cancel all the pending transfers */
++ if (fsg->intreq_busy)
++ usb_ep_dequeue(fsg->intr_in, fsg->intreq);
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ bh = &fsg->buffhds[i];
++ if (bh->inreq_busy)
++ usb_ep_dequeue(fsg->bulk_in, bh->inreq);
++ if (bh->outreq_busy)
++ usb_ep_dequeue(fsg->bulk_out, bh->outreq);
++ }
++
++ /* Wait until everything is idle */
++ for (;;) {
++ num_active = fsg->intreq_busy;
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ bh = &fsg->buffhds[i];
++ num_active += bh->inreq_busy + bh->outreq_busy;
++ }
++ if (num_active == 0)
++ break;
++ if (sleep_thread(fsg))
++ return;
++ }
++
++ /* Clear out the controller's fifos */
++ if (fsg->bulk_in_enabled)
++ usb_ep_fifo_flush(fsg->bulk_in);
++ if (fsg->bulk_out_enabled)
++ usb_ep_fifo_flush(fsg->bulk_out);
++ if (fsg->intr_in_enabled)
++ usb_ep_fifo_flush(fsg->intr_in);
++
++ /* Reset the I/O buffer states and pointers, the SCSI
++ * state, and the exception. Then invoke the handler. */
++ spin_lock_irq(&fsg->lock);
++
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ bh = &fsg->buffhds[i];
++ bh->state = BUF_STATE_EMPTY;
++ }
++ fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain =
++ &fsg->buffhds[0];
++
++ exception_req_tag = fsg->exception_req_tag;
++ new_config = fsg->new_config;
++ old_state = fsg->state;
++
++ if (old_state == FSG_STATE_ABORT_BULK_OUT)
++ fsg->state = FSG_STATE_STATUS_PHASE;
++ else {
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ curlun->prevent_medium_removal = 0;
++ curlun->sense_data = curlun->unit_attention_data =
++ SS_NO_SENSE;
++ curlun->sense_data_info = 0;
++ curlun->info_valid = 0;
++ }
++ fsg->state = FSG_STATE_IDLE;
++ }
++ spin_unlock_irq(&fsg->lock);
++
++ /* Carry out any extra actions required for the exception */
++ switch (old_state) {
++ default:
++ break;
++
++ case FSG_STATE_ABORT_BULK_OUT:
++ send_status(fsg);
++ spin_lock_irq(&fsg->lock);
++ if (fsg->state == FSG_STATE_STATUS_PHASE)
++ fsg->state = FSG_STATE_IDLE;
++ spin_unlock_irq(&fsg->lock);
++ break;
++
++ case FSG_STATE_RESET:
++ /* In case we were forced against our will to halt a
++ * bulk endpoint, clear the halt now. (The SuperH UDC
++ * requires this.) */
++ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
++ usb_ep_clear_halt(fsg->bulk_in);
++
++ if (transport_is_bbb()) {
++ if (fsg->ep0_req_tag == exception_req_tag)
++ ep0_queue(fsg); // Complete the status stage
++
++ } else if (transport_is_cbi())
++ send_status(fsg); // Status by interrupt pipe
++
++ /* Technically this should go here, but it would only be
++ * a waste of time. Ditto for the INTERFACE_CHANGE and
++ * CONFIG_CHANGE cases. */
++ // for (i = 0; i < fsg->nluns; ++i)
++ // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED;
++ break;
++
++ case FSG_STATE_INTERFACE_CHANGE:
++ rc = do_set_interface(fsg, 0);
++ if (fsg->ep0_req_tag != exception_req_tag)
++ break;
++ if (rc != 0) // STALL on errors
++ fsg_set_halt(fsg, fsg->ep0);
++ else // Complete the status stage
++ ep0_queue(fsg);
++ break;
++
++ case FSG_STATE_CONFIG_CHANGE:
++ rc = do_set_config(fsg, new_config);
++ if (fsg->ep0_req_tag != exception_req_tag)
++ break;
++ if (rc != 0) // STALL on errors
++ fsg_set_halt(fsg, fsg->ep0);
++ else // Complete the status stage
++ ep0_queue(fsg);
++ break;
++
++ case FSG_STATE_DISCONNECT:
++ for (i = 0; i < fsg->nluns; ++i)
++ fsg_lun_fsync_sub(fsg->luns + i);
++ do_set_config(fsg, 0); // Unconfigured state
++ break;
++
++ case FSG_STATE_EXIT:
++ case FSG_STATE_TERMINATED:
++ do_set_config(fsg, 0); // Free resources
++ spin_lock_irq(&fsg->lock);
++ fsg->state = FSG_STATE_TERMINATED; // Stop the thread
++ spin_unlock_irq(&fsg->lock);
++ break;
++ }
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static int fsg_main_thread(void *fsg_)
++{
++ struct fsg_dev *fsg = fsg_;
++
++ /* Allow the thread to be killed by a signal, but set the signal mask
++ * to block everything but INT, TERM, KILL, and USR1. */
++ allow_signal(SIGINT);
++ allow_signal(SIGTERM);
++ allow_signal(SIGKILL);
++ allow_signal(SIGUSR1);
++
++ /* Allow the thread to be frozen */
++ set_freezable();
++
++ /* Arrange for userspace references to be interpreted as kernel
++ * pointers. That way we can pass a kernel pointer to a routine
++ * that expects a __user pointer and it will work okay. */
++ set_fs(get_ds());
++
++ /* The main loop */
++ while (fsg->state != FSG_STATE_TERMINATED) {
++ if (exception_in_progress(fsg) || signal_pending(current)) {
++ handle_exception(fsg);
++ continue;
++ }
++
++ if (!fsg->running) {
++ sleep_thread(fsg);
++ continue;
++ }
++
++ if (get_next_command(fsg))
++ continue;
++
++ spin_lock_irq(&fsg->lock);
++ if (!exception_in_progress(fsg))
++ fsg->state = FSG_STATE_DATA_PHASE;
++ spin_unlock_irq(&fsg->lock);
++
++ if (do_scsi_command(fsg) || finish_reply(fsg))
++ continue;
++
++ spin_lock_irq(&fsg->lock);
++ if (!exception_in_progress(fsg))
++ fsg->state = FSG_STATE_STATUS_PHASE;
++ spin_unlock_irq(&fsg->lock);
++
++ if (send_status(fsg))
++ continue;
++
++ spin_lock_irq(&fsg->lock);
++ if (!exception_in_progress(fsg))
++ fsg->state = FSG_STATE_IDLE;
++ spin_unlock_irq(&fsg->lock);
++ }
++
++ spin_lock_irq(&fsg->lock);
++ fsg->thread_task = NULL;
++ spin_unlock_irq(&fsg->lock);
++
++ /* If we are exiting because of a signal, unregister the
++ * gadget driver. */
++ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
++ usb_gadget_unregister_driver(&fsg_driver);
++
++ /* Let the unbind and cleanup routines know the thread has exited */
++ complete_and_exit(&fsg->thread_notifier, 0);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++
++/* The write permissions and store_xxx pointers are set in fsg_bind() */
++static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
++static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
++static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
++
++
++/*-------------------------------------------------------------------------*/
++
++static void fsg_release(struct kref *ref)
++{
++ struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
++
++ kfree(fsg->luns);
++ kfree(fsg);
++}
++
++static void lun_release(struct device *dev)
++{
++ struct rw_semaphore *filesem = dev_get_drvdata(dev);
++ struct fsg_dev *fsg =
++ container_of(filesem, struct fsg_dev, filesem);
++
++ kref_put(&fsg->ref, fsg_release);
++}
++
++static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++ int i;
++ struct fsg_lun *curlun;
++ struct usb_request *req = fsg->ep0req;
++
++ DBG(fsg, "unbind\n");
++ clear_bit(REGISTERED, &fsg->atomic_bitflags);
++
++ /* If the thread isn't already dead, tell it to exit now */
++ if (fsg->state != FSG_STATE_TERMINATED) {
++ raise_exception(fsg, FSG_STATE_EXIT);
++ wait_for_completion(&fsg->thread_notifier);
++
++ /* The cleanup routine waits for this completion also */
++ complete(&fsg->thread_notifier);
++ }
++
++ /* Unregister the sysfs attribute files and the LUNs */
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ if (curlun->registered) {
++ device_remove_file(&curlun->dev, &dev_attr_nofua);
++ device_remove_file(&curlun->dev, &dev_attr_ro);
++ device_remove_file(&curlun->dev, &dev_attr_file);
++ fsg_lun_close(curlun);
++ device_unregister(&curlun->dev);
++ curlun->registered = 0;
++ }
++ }
++
++ /* Free the data buffers */
++ for (i = 0; i < fsg_num_buffers; ++i)
++ kfree(fsg->buffhds[i].buf);
++
++ /* Free the request and buffer for endpoint 0 */
++ if (req) {
++ kfree(req->buf);
++ usb_ep_free_request(fsg->ep0, req);
++ }
++
++ set_gadget_data(gadget, NULL);
++}
++
++
++static int __init check_parameters(struct fsg_dev *fsg)
++{
++ int prot;
++ int gcnum;
++
++ /* Store the default values */
++ mod_data.transport_type = USB_PR_BULK;
++ mod_data.transport_name = "Bulk-only";
++ mod_data.protocol_type = USB_SC_SCSI;
++ mod_data.protocol_name = "Transparent SCSI";
++
++ /* Some peripheral controllers are known not to be able to
++ * halt bulk endpoints correctly. If one of them is present,
++ * disable stalls.
++ */
++ if (gadget_is_at91(fsg->gadget))
++ mod_data.can_stall = 0;
++
++ if (mod_data.release == 0xffff) { // Parameter wasn't set
++ gcnum = usb_gadget_controller_number(fsg->gadget);
++ if (gcnum >= 0)
++ mod_data.release = 0x0300 + gcnum;
++ else {
++ WARNING(fsg, "controller '%s' not recognized\n",
++ fsg->gadget->name);
++ mod_data.release = 0x0399;
++ }
++ }
++
++ prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
++
++#ifdef CONFIG_USB_FILE_STORAGE_TEST
++ if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
++ ; // Use default setting
++ } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) {
++ mod_data.transport_type = USB_PR_CB;
++ mod_data.transport_name = "Control-Bulk";
++ } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) {
++ mod_data.transport_type = USB_PR_CBI;
++ mod_data.transport_name = "Control-Bulk-Interrupt";
++ } else {
++ ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm);
++ return -EINVAL;
++ }
++
++ if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 ||
++ prot == USB_SC_SCSI) {
++ ; // Use default setting
++ } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 ||
++ prot == USB_SC_RBC) {
++ mod_data.protocol_type = USB_SC_RBC;
++ mod_data.protocol_name = "RBC";
++ } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 ||
++ strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 ||
++ prot == USB_SC_8020) {
++ mod_data.protocol_type = USB_SC_8020;
++ mod_data.protocol_name = "8020i (ATAPI)";
++ } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 ||
++ prot == USB_SC_QIC) {
++ mod_data.protocol_type = USB_SC_QIC;
++ mod_data.protocol_name = "QIC-157";
++ } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 ||
++ prot == USB_SC_UFI) {
++ mod_data.protocol_type = USB_SC_UFI;
++ mod_data.protocol_name = "UFI";
++ } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 ||
++ prot == USB_SC_8070) {
++ mod_data.protocol_type = USB_SC_8070;
++ mod_data.protocol_name = "8070i";
++ } else {
++ ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm);
++ return -EINVAL;
++ }
++
++ mod_data.buflen &= PAGE_CACHE_MASK;
++ if (mod_data.buflen <= 0) {
++ ERROR(fsg, "invalid buflen\n");
++ return -ETOOSMALL;
++ }
++
++#endif /* CONFIG_USB_FILE_STORAGE_TEST */
++
++ /* Serial string handling.
++ * On a real device, the serial string would be loaded
++ * from permanent storage. */
++ if (mod_data.serial) {
++ const char *ch;
++ unsigned len = 0;
++
++ /* Sanity check :
++ * The CB[I] specification limits the serial string to
++ * 12 uppercase hexadecimal characters.
++ * BBB need at least 12 uppercase hexadecimal characters,
++ * with a maximum of 126. */
++ for (ch = mod_data.serial; *ch; ++ch) {
++ ++len;
++ if ((*ch < '0' || *ch > '9') &&
++ (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
++ WARNING(fsg,
++ "Invalid serial string character: %c\n",
++ *ch);
++ goto no_serial;
++ }
++ }
++ if (len > 126 ||
++ (mod_data.transport_type == USB_PR_BULK && len < 12) ||
++ (mod_data.transport_type != USB_PR_BULK && len > 12)) {
++ WARNING(fsg, "Invalid serial string length!\n");
++ goto no_serial;
++ }
++ fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
++ } else {
++ WARNING(fsg, "No serial-number string provided!\n");
++ no_serial:
++ device_desc.iSerialNumber = 0;
++ }
++
++ return 0;
++}
++
++
++static int __init fsg_bind(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = the_fsg;
++ int rc;
++ int i;
++ struct fsg_lun *curlun;
++ struct usb_ep *ep;
++ struct usb_request *req;
++ char *pathbuf, *p;
++
++ fsg->gadget = gadget;
++ set_gadget_data(gadget, fsg);
++ fsg->ep0 = gadget->ep0;
++ fsg->ep0->driver_data = fsg;
++
++ if ((rc = check_parameters(fsg)) != 0)
++ goto out;
++
++ if (mod_data.removable) { // Enable the store_xxx attributes
++ dev_attr_file.attr.mode = 0644;
++ dev_attr_file.store = fsg_store_file;
++ if (!mod_data.cdrom) {
++ dev_attr_ro.attr.mode = 0644;
++ dev_attr_ro.store = fsg_store_ro;
++ }
++ }
++
++ /* Only for removable media? */
++ dev_attr_nofua.attr.mode = 0644;
++ dev_attr_nofua.store = fsg_store_nofua;
++
++ /* Find out how many LUNs there should be */
++ i = mod_data.nluns;
++ if (i == 0)
++ i = max(mod_data.num_filenames, 1u);
++ if (i > FSG_MAX_LUNS) {
++ ERROR(fsg, "invalid number of LUNs: %d\n", i);
++ rc = -EINVAL;
++ goto out;
++ }
++
++ /* Create the LUNs, open their backing files, and register the
++ * LUN devices in sysfs. */
++ fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL);
++ if (!fsg->luns) {
++ rc = -ENOMEM;
++ goto out;
++ }
++ fsg->nluns = i;
++
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ curlun->cdrom = !!mod_data.cdrom;
++ curlun->ro = mod_data.cdrom || mod_data.ro[i];
++ curlun->initially_ro = curlun->ro;
++ curlun->removable = mod_data.removable;
++ curlun->nofua = mod_data.nofua[i];
++ curlun->dev.release = lun_release;
++ curlun->dev.parent = &gadget->dev;
++ curlun->dev.driver = &fsg_driver.driver;
++ dev_set_drvdata(&curlun->dev, &fsg->filesem);
++ dev_set_name(&curlun->dev,"%s-lun%d",
++ dev_name(&gadget->dev), i);
++
++ kref_get(&fsg->ref);
++ rc = device_register(&curlun->dev);
++ if (rc) {
++ INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
++ put_device(&curlun->dev);
++ goto out;
++ }
++ curlun->registered = 1;
++
++ rc = device_create_file(&curlun->dev, &dev_attr_ro);
++ if (rc)
++ goto out;
++ rc = device_create_file(&curlun->dev, &dev_attr_nofua);
++ if (rc)
++ goto out;
++ rc = device_create_file(&curlun->dev, &dev_attr_file);
++ if (rc)
++ goto out;
++
++ if (mod_data.file[i] && *mod_data.file[i]) {
++ rc = fsg_lun_open(curlun, mod_data.file[i]);
++ if (rc)
++ goto out;
++ } else if (!mod_data.removable) {
++ ERROR(fsg, "no file given for LUN%d\n", i);
++ rc = -EINVAL;
++ goto out;
++ }
++ }
++
++ /* Find all the endpoints we will use */
++ usb_ep_autoconfig_reset(gadget);
++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
++ if (!ep)
++ goto autoconf_fail;
++ ep->driver_data = fsg; // claim the endpoint
++ fsg->bulk_in = ep;
++
++ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
++ if (!ep)
++ goto autoconf_fail;
++ ep->driver_data = fsg; // claim the endpoint
++ fsg->bulk_out = ep;
++
++ if (transport_is_cbi()) {
++ ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc);
++ if (!ep)
++ goto autoconf_fail;
++ ep->driver_data = fsg; // claim the endpoint
++ fsg->intr_in = ep;
++ }
++
++ /* Fix up the descriptors */
++ device_desc.idVendor = cpu_to_le16(mod_data.vendor);
++ device_desc.idProduct = cpu_to_le16(mod_data.product);
++ device_desc.bcdDevice = cpu_to_le16(mod_data.release);
++
++ i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
++ fsg_intf_desc.bNumEndpoints = i;
++ fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type;
++ fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type;
++ fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
++
++ if (gadget_is_dualspeed(gadget)) {
++ fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
++
++ /* Assume endpoint addresses are the same for both speeds */
++ fsg_hs_bulk_in_desc.bEndpointAddress =
++ fsg_fs_bulk_in_desc.bEndpointAddress;
++ fsg_hs_bulk_out_desc.bEndpointAddress =
++ fsg_fs_bulk_out_desc.bEndpointAddress;
++ fsg_hs_intr_in_desc.bEndpointAddress =
++ fsg_fs_intr_in_desc.bEndpointAddress;
++ }
++
++ if (gadget_is_superspeed(gadget)) {
++ unsigned max_burst;
++
++ fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
++
++ /* Calculate bMaxBurst, we know packet size is 1024 */
++ max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
++
++ /* Assume endpoint addresses are the same for both speeds */
++ fsg_ss_bulk_in_desc.bEndpointAddress =
++ fsg_fs_bulk_in_desc.bEndpointAddress;
++ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
++
++ fsg_ss_bulk_out_desc.bEndpointAddress =
++ fsg_fs_bulk_out_desc.bEndpointAddress;
++ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
++ }
++
++ if (gadget_is_otg(gadget))
++ fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
++
++ rc = -ENOMEM;
++
++ /* Allocate the request and buffer for endpoint 0 */
++ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
++ if (!req)
++ goto out;
++ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
++ if (!req->buf)
++ goto out;
++ req->complete = ep0_complete;
++
++ /* Allocate the data buffers */
++ for (i = 0; i < fsg_num_buffers; ++i) {
++ struct fsg_buffhd *bh = &fsg->buffhds[i];
++
++ /* Allocate for the bulk-in endpoint. We assume that
++ * the buffer will also work with the bulk-out (and
++ * interrupt-in) endpoint. */
++ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
++ if (!bh->buf)
++ goto out;
++ bh->next = bh + 1;
++ }
++ fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
++
++ /* This should reflect the actual gadget power source */
++ usb_gadget_set_selfpowered(gadget);
++
++ snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer,
++ "%s %s with %s",
++ init_utsname()->sysname, init_utsname()->release,
++ gadget->name);
++
++ fsg->thread_task = kthread_create(fsg_main_thread, fsg,
++ "file-storage-gadget");
++ if (IS_ERR(fsg->thread_task)) {
++ rc = PTR_ERR(fsg->thread_task);
++ goto out;
++ }
++
++ INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
++ INFO(fsg, "NOTE: This driver is deprecated. "
++ "Consider using g_mass_storage instead.\n");
++ INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
++
++ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
++ for (i = 0; i < fsg->nluns; ++i) {
++ curlun = &fsg->luns[i];
++ if (fsg_lun_is_open(curlun)) {
++ p = NULL;
++ if (pathbuf) {
++ p = d_path(&curlun->filp->f_path,
++ pathbuf, PATH_MAX);
++ if (IS_ERR(p))
++ p = NULL;
++ }
++ LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
++ curlun->ro, curlun->nofua, (p ? p : "(error)"));
++ }
++ }
++ kfree(pathbuf);
++
++ DBG(fsg, "transport=%s (x%02x)\n",
++ mod_data.transport_name, mod_data.transport_type);
++ DBG(fsg, "protocol=%s (x%02x)\n",
++ mod_data.protocol_name, mod_data.protocol_type);
++ DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
++ mod_data.vendor, mod_data.product, mod_data.release);
++ DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
++ mod_data.removable, mod_data.can_stall,
++ mod_data.cdrom, mod_data.buflen);
++ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
++
++ set_bit(REGISTERED, &fsg->atomic_bitflags);
++
++ /* Tell the thread to start working */
++ wake_up_process(fsg->thread_task);
++ return 0;
++
++autoconf_fail:
++ ERROR(fsg, "unable to autoconfigure all endpoints\n");
++ rc = -ENOTSUPP;
++
++out:
++ fsg->state = FSG_STATE_TERMINATED; // The thread is dead
++ fsg_unbind(gadget);
++ complete(&fsg->thread_notifier);
++ return rc;
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static void fsg_suspend(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++
++ DBG(fsg, "suspend\n");
++ set_bit(SUSPENDED, &fsg->atomic_bitflags);
++}
++
++static void fsg_resume(struct usb_gadget *gadget)
++{
++ struct fsg_dev *fsg = get_gadget_data(gadget);
++
++ DBG(fsg, "resume\n");
++ clear_bit(SUSPENDED, &fsg->atomic_bitflags);
++}
++
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_gadget_driver fsg_driver = {
++ .max_speed = USB_SPEED_SUPER,
++ .function = (char *) fsg_string_product,
++ .unbind = fsg_unbind,
++ .disconnect = fsg_disconnect,
++ .setup = fsg_setup,
++ .suspend = fsg_suspend,
++ .resume = fsg_resume,
++
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ // .release = ...
++ // .suspend = ...
++ // .resume = ...
++ },
++};
++
++
++static int __init fsg_alloc(void)
++{
++ struct fsg_dev *fsg;
++
++ fsg = kzalloc(sizeof *fsg +
++ fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
++
++ if (!fsg)
++ return -ENOMEM;
++ spin_lock_init(&fsg->lock);
++ init_rwsem(&fsg->filesem);
++ kref_init(&fsg->ref);
++ init_completion(&fsg->thread_notifier);
++
++ the_fsg = fsg;
++ return 0;
++}
++
++
++static int __init fsg_init(void)
++{
++ int rc;
++ struct fsg_dev *fsg;
++
++ rc = fsg_num_buffers_validate();
++ if (rc != 0)
++ return rc;
++
++ if ((rc = fsg_alloc()) != 0)
++ return rc;
++ fsg = the_fsg;
++ if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
++ kref_put(&fsg->ref, fsg_release);
++ return rc;
++}
++module_init(fsg_init);
++
++
++static void __exit fsg_cleanup(void)
++{
++ struct fsg_dev *fsg = the_fsg;
++
++ /* Unregister the driver iff the thread hasn't already done so */
++ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
++ usb_gadget_unregister_driver(&fsg_driver);
++
++ /* Wait for the thread to finish up */
++ wait_for_completion(&fsg->thread_notifier);
++
++ kref_put(&fsg->ref, fsg_release);
++}
++module_exit(fsg_cleanup);
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index d809671c5fea..991b6a44d140 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -748,6 +748,16 @@ config USB_HWA_HCD
+ To compile this driver a module, choose M here: the module
+ will be called "hwa-hc".
+
++config USB_DWCOTG
++ bool "Synopsis DWC host support"
++ depends on USB && (FIQ || ARM64)
++ help
++ The Synopsis DWC controller is a dual-role
++ host/peripheral/OTG ("On The Go") USB controllers.
++
++ Enable this option to support this IP in host controller mode.
++ If unsure, say N.
++
+ config USB_IMX21_HCD
+ tristate "i.MX21 HCD support"
+ depends on ARM && ARCH_MXC
+diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
+index 84514f71ae44..31bc2d78a4c3 100644
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -83,6 +83,8 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
+ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
+ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
+ obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
++
++obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/
+ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
+ obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
+ obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
+diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile
+new file mode 100644
+index 000000000000..f10d466d1aea
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/Makefile
+@@ -0,0 +1,58 @@
++#
++# Makefile for DWC_common library
++#
++
++ifneq ($(KERNELRELEASE),)
++
++ccflags-y += -DDWC_LINUX
++#ccflags-y += -DDEBUG
++#ccflags-y += -DDWC_DEBUG_REGS
++#ccflags-y += -DDWC_DEBUG_MEMORY
++
++ccflags-y += -DDWC_LIBMODULE
++ccflags-y += -DDWC_CCLIB
++#ccflags-y += -DDWC_CRYPTOLIB
++ccflags-y += -DDWC_NOTIFYLIB
++ccflags-y += -DDWC_UTFLIB
++
++obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o
++dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
++ dwc_crypto.o dwc_notifier.o \
++ dwc_common_linux.o dwc_mem.o
++
++kernrelwd := $(subst ., ,$(KERNELRELEASE))
++kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd))
++
++ifneq ($(kernrel3),2.6.20)
++# grayg - I only know that we use ccflags-y in 2.6.31 actually
++ccflags-y += $(CPPFLAGS)
++endif
++
++else
++
++#ifeq ($(KDIR),)
++#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
++#endif
++
++ifeq ($(ARCH),)
++$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
++ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
++endif
++
++ifeq ($(DOXYGEN),)
++DOXYGEN := doxygen
++endif
++
++default:
++ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
++
++docs: $(wildcard *.[hc]) doc/doxygen.cfg
++ $(DOXYGEN) doc/doxygen.cfg
++
++tags: $(wildcard *.[hc])
++ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
++
++endif
++
++clean:
++ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
+diff --git a/drivers/usb/host/dwc_common_port/Makefile.fbsd b/drivers/usb/host/dwc_common_port/Makefile.fbsd
+new file mode 100644
+index 000000000000..45db9915b9d3
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd
+@@ -0,0 +1,17 @@
++CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include
++CFLAGS += -DDWC_FREEBSD
++CFLAGS += -DDEBUG
++#CFLAGS += -DDWC_DEBUG_REGS
++#CFLAGS += -DDWC_DEBUG_MEMORY
++
++#CFLAGS += -DDWC_LIBMODULE
++#CFLAGS += -DDWC_CCLIB
++#CFLAGS += -DDWC_CRYPTOLIB
++#CFLAGS += -DDWC_NOTIFYLIB
++#CFLAGS += -DDWC_UTFLIB
++
++KMOD = dwc_common_port_lib
++SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \
++ dwc_common_fbsd.c dwc_mem.c
++
++.include <bsd.kmod.mk>
+diff --git a/drivers/usb/host/dwc_common_port/Makefile.linux b/drivers/usb/host/dwc_common_port/Makefile.linux
+new file mode 100644
+index 000000000000..0cef7b461bd5
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/Makefile.linux
+@@ -0,0 +1,49 @@
++#
++# Makefile for DWC_common library
++#
++ifneq ($(KERNELRELEASE),)
++
++ccflags-y += -DDWC_LINUX
++#ccflags-y += -DDEBUG
++#ccflags-y += -DDWC_DEBUG_REGS
++#ccflags-y += -DDWC_DEBUG_MEMORY
++
++ccflags-y += -DDWC_LIBMODULE
++ccflags-y += -DDWC_CCLIB
++ccflags-y += -DDWC_CRYPTOLIB
++ccflags-y += -DDWC_NOTIFYLIB
++ccflags-y += -DDWC_UTFLIB
++
++obj-m := dwc_common_port_lib.o
++dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \
++ dwc_crypto.o dwc_notifier.o \
++ dwc_common_linux.o dwc_mem.o
++
++else
++
++ifeq ($(KDIR),)
++$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment)
++endif
++
++ifeq ($(ARCH),)
++$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \
++ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-")
++endif
++
++ifeq ($(DOXYGEN),)
++DOXYGEN := doxygen
++endif
++
++default:
++ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
++
++docs: $(wildcard *.[hc]) doc/doxygen.cfg
++ $(DOXYGEN) doc/doxygen.cfg
++
++tags: $(wildcard *.[hc])
++ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h)
++
++endif
++
++clean:
++ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/
+diff --git a/drivers/usb/host/dwc_common_port/changes.txt b/drivers/usb/host/dwc_common_port/changes.txt
+new file mode 100644
+index 000000000000..f6839f92c276
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/changes.txt
+@@ -0,0 +1,174 @@
++
++dwc_read_reg32() and friends now take an additional parameter, a pointer to an
++IO context struct. The IO context struct should live in an os-dependent struct
++in your driver. As an example, the dwc_usb3 driver has an os-dependent struct
++named 'os_dep' embedded in the main device struct. So there these calls look
++like this:
++
++ dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg);
++
++ dwc_write_reg32(&usb3_dev->os_dep.ioctx,
++ &pcd->dev_global_regs->dcfg, 0);
++
++Note that for the existing Linux driver ports, it is not necessary to actually
++define the 'ioctx' member in the os-dependent struct. Since Linux does not
++require an IO context, its macros for dwc_read_reg32() and friends do not
++use the context pointer, so it is optimized away by the compiler. But it is
++necessary to add the pointer parameter to all of the call sites, to be ready
++for any future ports (such as FreeBSD) which do require an IO context.
++
++
++Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now
++take an additional parameter, a pointer to a memory context. Examples:
++
++ addr = dwc_alloc(&usb3_dev->os_dep.memctx, size);
++
++ dwc_free(&usb3_dev->os_dep.memctx, addr);
++
++Again, for the Linux ports, it is not necessary to actually define the memctx
++member, but it is necessary to add the pointer parameter to all of the call
++sites.
++
++
++Same for dwc_dma_alloc() and dwc_dma_free(). Examples:
++
++ virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr);
++
++ dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr);
++
++
++Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples:
++
++ mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx);
++
++ dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex);
++
++
++Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples:
++
++ lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx);
++
++ dwc_spinlock_free(&usb3_dev->osdep.splctx, lock);
++
++
++Same for dwc_timer_alloc(). Example:
++
++ timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1",
++ cb_func, cb_data);
++
++
++Same for dwc_waitq_alloc(). Example:
++
++ waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx);
++
++
++Same for dwc_thread_run(). Example:
++
++ thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func,
++ "dwc_usb3_thd1", data);
++
++
++Same for dwc_workq_alloc(). Example:
++
++ workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1");
++
++
++Same for dwc_task_alloc(). Example:
++
++ task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1",
++ cb_func, cb_data);
++
++
++In addition to the context pointer additions, a few core functions have had
++other changes made to their parameters:
++
++The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore()
++has been changed from a uint64_t to a dwc_irqflags_t.
++
++dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the
++FreeBSD equivalent of that function requires it.
++
++And, in addition to the context pointer, dwc_task_alloc() also adds a
++'char *name' parameter, to be consistent with dwc_thread_run() and
++dwc_workq_alloc(), and because the FreeBSD equivalent of that function
++requires a unique name.
++
++
++Here is a complete list of the core functions that now take a pointer to a
++context as their first parameter:
++
++ dwc_read_reg32
++ dwc_read_reg64
++ dwc_write_reg32
++ dwc_write_reg64
++ dwc_modify_reg32
++ dwc_modify_reg64
++ dwc_alloc
++ dwc_alloc_atomic
++ dwc_strdup
++ dwc_free
++ dwc_dma_alloc
++ dwc_dma_free
++ dwc_mutex_alloc
++ dwc_mutex_free
++ dwc_spinlock_alloc
++ dwc_spinlock_free
++ dwc_timer_alloc
++ dwc_waitq_alloc
++ dwc_thread_run
++ dwc_workq_alloc
++ dwc_task_alloc Also adds a 'char *name' as its 2nd parameter
++
++And here are the core functions that have other changes to their parameters:
++
++ dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *'
++ dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t'
++ dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter
++
++
++
++The changes to the core functions also require some of the other library
++functions to change:
++
++ dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx'
++ (for memory allocation) as the 1st param and a 'void *mtxctx'
++ (for mutex allocation) as the 2nd param.
++
++ dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(),
++ dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a
++ 'void *memctx' as the 1st param.
++
++ dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a
++ 'void *memctx' as the 1st param.
++
++ dwc_modpow() now takes a 'void *memctx' as the 1st param.
++
++ dwc_alloc_notification_manager() now takes a 'void *memctx' as the
++ 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd
++ param, and also now returns an integer value that is non-zero if
++ allocation of its data structures or work queue fails.
++
++ dwc_register_notifier() now takes a 'void *memctx' as the 1st param.
++
++ dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first
++ param, and also now returns an integer value that is non-zero if
++ allocation of its data structures fails.
++
++
++
++Other miscellaneous changes:
++
++The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to
++DWC_DEBUG_MEMORY and DWC_DEBUG_REGS.
++
++The following #define's have been added to allow selectively compiling library
++features:
++
++ DWC_CCLIB
++ DWC_CRYPTOLIB
++ DWC_NOTIFYLIB
++ DWC_UTFLIB
++
++A DWC_LIBMODULE #define has also been added. If this is not defined, then the
++module code in dwc_common_linux.c is not compiled in. This allows linking the
++library code directly into a driver module, instead of as a standalone module.
+diff --git a/drivers/usb/host/dwc_common_port/doc/doxygen.cfg b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
+new file mode 100644
+index 000000000000..89aa887af29d
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg
+@@ -0,0 +1,270 @@
++# Doxyfile 1.4.5
++
++#---------------------------------------------------------------------------
++# Project related configuration options
++#---------------------------------------------------------------------------
++PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB"
++PROJECT_NUMBER =
++OUTPUT_DIRECTORY = doc
++CREATE_SUBDIRS = NO
++OUTPUT_LANGUAGE = English
++BRIEF_MEMBER_DESC = YES
++REPEAT_BRIEF = YES
++ABBREVIATE_BRIEF = "The $name class" \
++ "The $name widget" \
++ "The $name file" \
++ is \
++ provides \
++ specifies \
++ contains \
++ represents \
++ a \
++ an \
++ the
++ALWAYS_DETAILED_SEC = YES
++INLINE_INHERITED_MEMB = NO
++FULL_PATH_NAMES = NO
++STRIP_FROM_PATH = ..
++STRIP_FROM_INC_PATH =
++SHORT_NAMES = NO
++JAVADOC_AUTOBRIEF = YES
++MULTILINE_CPP_IS_BRIEF = NO
++DETAILS_AT_TOP = YES
++INHERIT_DOCS = YES
++SEPARATE_MEMBER_PAGES = NO
++TAB_SIZE = 8
++ALIASES =
++OPTIMIZE_OUTPUT_FOR_C = YES
++OPTIMIZE_OUTPUT_JAVA = NO
++BUILTIN_STL_SUPPORT = NO
++DISTRIBUTE_GROUP_DOC = NO
++SUBGROUPING = NO
++#---------------------------------------------------------------------------
++# Build related configuration options
++#---------------------------------------------------------------------------
++EXTRACT_ALL = NO
++EXTRACT_PRIVATE = NO
++EXTRACT_STATIC = YES
++EXTRACT_LOCAL_CLASSES = NO
++EXTRACT_LOCAL_METHODS = NO
++HIDE_UNDOC_MEMBERS = NO
++HIDE_UNDOC_CLASSES = NO
++HIDE_FRIEND_COMPOUNDS = NO
++HIDE_IN_BODY_DOCS = NO
++INTERNAL_DOCS = NO
++CASE_SENSE_NAMES = YES
++HIDE_SCOPE_NAMES = NO
++SHOW_INCLUDE_FILES = NO
++INLINE_INFO = YES
++SORT_MEMBER_DOCS = NO
++SORT_BRIEF_DOCS = NO
++SORT_BY_SCOPE_NAME = NO
++GENERATE_TODOLIST = YES
++GENERATE_TESTLIST = YES
++GENERATE_BUGLIST = YES
++GENERATE_DEPRECATEDLIST= YES
++ENABLED_SECTIONS =
++MAX_INITIALIZER_LINES = 30
++SHOW_USED_FILES = YES
++SHOW_DIRECTORIES = YES
++FILE_VERSION_FILTER =
++#---------------------------------------------------------------------------
++# configuration options related to warning and progress messages
++#---------------------------------------------------------------------------
++QUIET = YES
++WARNINGS = YES
++WARN_IF_UNDOCUMENTED = NO
++WARN_IF_DOC_ERROR = YES
++WARN_NO_PARAMDOC = YES
++WARN_FORMAT = "$file:$line: $text"
++WARN_LOGFILE =
++#---------------------------------------------------------------------------
++# configuration options related to the input files
++#---------------------------------------------------------------------------
++INPUT = .
++FILE_PATTERNS = *.c \
++ *.cc \
++ *.cxx \
++ *.cpp \
++ *.c++ \
++ *.d \
++ *.java \
++ *.ii \
++ *.ixx \
++ *.ipp \
++ *.i++ \
++ *.inl \
++ *.h \
++ *.hh \
++ *.hxx \
++ *.hpp \
++ *.h++ \
++ *.idl \
++ *.odl \
++ *.cs \
++ *.php \
++ *.php3 \
++ *.inc \
++ *.m \
++ *.mm \
++ *.dox \
++ *.py \
++ *.C \
++ *.CC \
++ *.C++ \
++ *.II \
++ *.I++ \
++ *.H \
++ *.HH \
++ *.H++ \
++ *.CS \
++ *.PHP \
++ *.PHP3 \
++ *.M \
++ *.MM \
++ *.PY
++RECURSIVE = NO
++EXCLUDE =
++EXCLUDE_SYMLINKS = NO
++EXCLUDE_PATTERNS =
++EXAMPLE_PATH =
++EXAMPLE_PATTERNS = *
++EXAMPLE_RECURSIVE = NO
++IMAGE_PATH =
++INPUT_FILTER =
++FILTER_PATTERNS =
++FILTER_SOURCE_FILES = NO
++#---------------------------------------------------------------------------
++# configuration options related to source browsing
++#---------------------------------------------------------------------------
++SOURCE_BROWSER = NO
++INLINE_SOURCES = NO
++STRIP_CODE_COMMENTS = YES
++REFERENCED_BY_RELATION = YES
++REFERENCES_RELATION = YES
++USE_HTAGS = NO
++VERBATIM_HEADERS = NO
++#---------------------------------------------------------------------------
++# configuration options related to the alphabetical class index
++#---------------------------------------------------------------------------
++ALPHABETICAL_INDEX = NO
++COLS_IN_ALPHA_INDEX = 5
++IGNORE_PREFIX =
++#---------------------------------------------------------------------------
++# configuration options related to the HTML output
++#---------------------------------------------------------------------------
++GENERATE_HTML = YES
++HTML_OUTPUT = html
++HTML_FILE_EXTENSION = .html
++HTML_HEADER =
++HTML_FOOTER =
++HTML_STYLESHEET =
++HTML_ALIGN_MEMBERS = YES
++GENERATE_HTMLHELP = NO
++CHM_FILE =
++HHC_LOCATION =
++GENERATE_CHI = NO
++BINARY_TOC = NO
++TOC_EXPAND = NO
++DISABLE_INDEX = NO
++ENUM_VALUES_PER_LINE = 4
++GENERATE_TREEVIEW = YES
++TREEVIEW_WIDTH = 250
++#---------------------------------------------------------------------------
++# configuration options related to the LaTeX output
++#---------------------------------------------------------------------------
++GENERATE_LATEX = NO
++LATEX_OUTPUT = latex
++LATEX_CMD_NAME = latex
++MAKEINDEX_CMD_NAME = makeindex
++COMPACT_LATEX = NO
++PAPER_TYPE = a4wide
++EXTRA_PACKAGES =
++LATEX_HEADER =
++PDF_HYPERLINKS = NO
++USE_PDFLATEX = NO
++LATEX_BATCHMODE = NO
++LATEX_HIDE_INDICES = NO
++#---------------------------------------------------------------------------
++# configuration options related to the RTF output
++#---------------------------------------------------------------------------
++GENERATE_RTF = NO
++RTF_OUTPUT = rtf
++COMPACT_RTF = NO
++RTF_HYPERLINKS = NO
++RTF_STYLESHEET_FILE =
++RTF_EXTENSIONS_FILE =
++#---------------------------------------------------------------------------
++# configuration options related to the man page output
++#---------------------------------------------------------------------------
++GENERATE_MAN = NO
++MAN_OUTPUT = man
++MAN_EXTENSION = .3
++MAN_LINKS = NO
++#---------------------------------------------------------------------------
++# configuration options related to the XML output
++#---------------------------------------------------------------------------
++GENERATE_XML = NO
++XML_OUTPUT = xml
++XML_SCHEMA =
++XML_DTD =
++XML_PROGRAMLISTING = YES
++#---------------------------------------------------------------------------
++# configuration options for the AutoGen Definitions output
++#---------------------------------------------------------------------------
++GENERATE_AUTOGEN_DEF = NO
++#---------------------------------------------------------------------------
++# configuration options related to the Perl module output
++#---------------------------------------------------------------------------
++GENERATE_PERLMOD = NO
++PERLMOD_LATEX = NO
++PERLMOD_PRETTY = YES
++PERLMOD_MAKEVAR_PREFIX =
++#---------------------------------------------------------------------------
++# Configuration options related to the preprocessor
++#---------------------------------------------------------------------------
++ENABLE_PREPROCESSING = YES
++MACRO_EXPANSION = NO
++EXPAND_ONLY_PREDEF = NO
++SEARCH_INCLUDES = YES
++INCLUDE_PATH =
++INCLUDE_FILE_PATTERNS =
++PREDEFINED = DEBUG DEBUG_MEMORY
++EXPAND_AS_DEFINED =
++SKIP_FUNCTION_MACROS = YES
++#---------------------------------------------------------------------------
++# Configuration::additions related to external references
++#---------------------------------------------------------------------------
++TAGFILES =
++GENERATE_TAGFILE =
++ALLEXTERNALS = NO
++EXTERNAL_GROUPS = YES
++PERL_PATH = /usr/bin/perl
++#---------------------------------------------------------------------------
++# Configuration options related to the dot tool
++#---------------------------------------------------------------------------
++CLASS_DIAGRAMS = YES
++HIDE_UNDOC_RELATIONS = YES
++HAVE_DOT = NO
++CLASS_GRAPH = YES
++COLLABORATION_GRAPH = YES
++GROUP_GRAPHS = YES
++UML_LOOK = NO
++TEMPLATE_RELATIONS = NO
++INCLUDE_GRAPH = NO
++INCLUDED_BY_GRAPH = YES
++CALL_GRAPH = NO
++GRAPHICAL_HIERARCHY = YES
++DIRECTORY_GRAPH = YES
++DOT_IMAGE_FORMAT = png
++DOT_PATH =
++DOTFILE_DIRS =
++MAX_DOT_GRAPH_DEPTH = 1000
++DOT_TRANSPARENT = NO
++DOT_MULTI_TARGETS = NO
++GENERATE_LEGEND = YES
++DOT_CLEANUP = YES
++#---------------------------------------------------------------------------
++# Configuration::additions related to the search engine
++#---------------------------------------------------------------------------
++SEARCHENGINE = NO
+diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.c b/drivers/usb/host/dwc_common_port/dwc_cc.c
+new file mode 100644
+index 000000000000..5ec2ae28698c
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_cc.c
+@@ -0,0 +1,532 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $
++ * $Revision: #4 $
++ * $Date: 2010/11/04 $
++ * $Change: 1621692 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifdef DWC_CCLIB
++
++#include "dwc_cc.h"
++
++typedef struct dwc_cc
++{
++ uint32_t uid;
++ uint8_t chid[16];
++ uint8_t cdid[16];
++ uint8_t ck[16];
++ uint8_t *name;
++ uint8_t length;
++ DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry;
++} dwc_cc_t;
++
++DWC_CIRCLEQ_HEAD(context_list, dwc_cc);
++
++/** The main structure for CC management. */
++struct dwc_cc_if
++{
++ dwc_mutex_t *mutex;
++ char *filename;
++
++ unsigned is_host:1;
++
++ dwc_notifier_t *notifier;
++
++ struct context_list list;
++};
++
++#ifdef DEBUG
++static inline void dump_bytes(char *name, uint8_t *bytes, int len)
++{
++ int i;
++ DWC_PRINTF("%s: ", name);
++ for (i=0; i<len; i++) {
++ DWC_PRINTF("%02x ", bytes[i]);
++ }
++ DWC_PRINTF("\n");
++}
++#else
++#define dump_bytes(x...)
++#endif
++
++static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length)
++{
++ dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t));
++ if (!cc) {
++ return NULL;
++ }
++ DWC_MEMSET(cc, 0, sizeof(dwc_cc_t));
++
++ if (name) {
++ cc->length = length;
++ cc->name = dwc_alloc(mem_ctx, length);
++ if (!cc->name) {
++ dwc_free(mem_ctx, cc);
++ return NULL;
++ }
++
++ DWC_MEMCPY(cc->name, name, length);
++ }
++
++ return cc;
++}
++
++static void free_cc(void *mem_ctx, dwc_cc_t *cc)
++{
++ if (cc->name) {
++ dwc_free(mem_ctx, cc->name);
++ }
++ dwc_free(mem_ctx, cc);
++}
++
++static uint32_t next_uid(dwc_cc_if_t *cc_if)
++{
++ uint32_t uid = 0;
++ dwc_cc_t *cc;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (cc->uid > uid) {
++ uid = cc->uid;
++ }
++ }
++
++ if (uid == 0) {
++ uid = 255;
++ }
++
++ return uid + 1;
++}
++
++static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid)
++{
++ dwc_cc_t *cc;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (cc->uid == uid) {
++ return cc;
++ }
++ }
++ return NULL;
++}
++
++static unsigned int cc_data_size(dwc_cc_if_t *cc_if)
++{
++ unsigned int size = 0;
++ dwc_cc_t *cc;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ size += (48 + 1);
++ if (cc->name) {
++ size += cc->length;
++ }
++ }
++ return size;
++}
++
++static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
++{
++ uint32_t uid = 0;
++ dwc_cc_t *cc;
++
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (DWC_MEMCMP(cc->chid, chid, 16) == 0) {
++ uid = cc->uid;
++ break;
++ }
++ }
++ return uid;
++}
++static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
++{
++ uint32_t uid = 0;
++ dwc_cc_t *cc;
++
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) {
++ uid = cc->uid;
++ break;
++ }
++ }
++ return uid;
++}
++
++/* Internal cc_add */
++static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++ dwc_cc_t *cc;
++ uint32_t uid;
++
++ if (cc_if->is_host) {
++ uid = cc_match_cdid(cc_if, cdid);
++ }
++ else {
++ uid = cc_match_chid(cc_if, chid);
++ }
++++
++ if (uid) {
++ DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length);
++ cc = cc_find(cc_if, uid);
++ }
++ else {
++ cc = alloc_cc(mem_ctx, name, length);
++ cc->uid = next_uid(cc_if);
++ DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry);
++ }
++
++ DWC_MEMCPY(&(cc->chid[0]), chid, 16);
++ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
++ DWC_MEMCPY(&(cc->ck[0]), ck, 16);
++++
++ DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length);
++ dump_bytes("CHID", cc->chid, 16);
++ dump_bytes("CDID", cc->cdid, 16);
++ dump_bytes("CK", cc->ck, 16);
++ return cc->uid;
++}
++
++/* Internal cc_clear */
++static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
++{
++ while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) {
++ dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list);
++ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
++ free_cc(mem_ctx, cc);
++ }
++}
++
++dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
++ dwc_notifier_t *notifier, unsigned is_host)
++{
++ dwc_cc_if_t *cc_if = NULL;
++
++ /* Allocate a common_cc_if structure */
++ cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t));
++
++ if (!cc_if)
++ return NULL;
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++ DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex);
++#else
++ cc_if->mutex = dwc_mutex_alloc(mtx_ctx);
++#endif
++ if (!cc_if->mutex) {
++ dwc_free(mem_ctx, cc_if);
++ return NULL;
++ }
++
++ DWC_CIRCLEQ_INIT(&cc_if->list);
++ cc_if->is_host = is_host;
++ cc_if->notifier = notifier;
++ return cc_if;
++}
++
++void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if)
++{
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++ DWC_MUTEX_FREE(cc_if->mutex);
++#else
++ dwc_mutex_free(mtx_ctx, cc_if->mutex);
++#endif
++ cc_clear(mem_ctx, cc_if);
++ dwc_free(mem_ctx, cc_if);
++}
++
++static void cc_changed(dwc_cc_if_t *cc_if)
++{
++ if (cc_if->notifier) {
++ dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if);
++ }
++}
++
++void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if)
++{
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc_clear(mem_ctx, cc_if);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ cc_changed(cc_if);
++}
++
++int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++ uint32_t uid;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ cc_changed(cc_if);
++
++ return uid;
++}
++
++void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
++{
++ dwc_cc_t* cc;
++
++ DWC_DEBUGC("Change connection context %d", id);
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (!cc) {
++ DWC_ERROR("Uid %d not found in cc list\n", id);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return;
++ }
++
++ if (chid) {
++ DWC_MEMCPY(&(cc->chid[0]), chid, 16);
++ }
++ if (cdid) {
++ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16);
++ }
++ if (ck) {
++ DWC_MEMCPY(&(cc->ck[0]), ck, 16);
++ }
++
++ if (name) {
++ if (cc->name) {
++ dwc_free(mem_ctx, cc->name);
++ }
++ cc->name = dwc_alloc(mem_ctx, length);
++ if (!cc->name) {
++ DWC_ERROR("Out of memory in dwc_cc_change()\n");
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return;
++ }
++ cc->length = length;
++ DWC_MEMCPY(cc->name, name, length);
++ }
++
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ cc_changed(cc_if);
++
++ DWC_DEBUGC("Changed connection context id=%d\n", id);
++ dump_bytes("New CHID", cc->chid, 16);
++ dump_bytes("New CDID", cc->cdid, 16);
++ dump_bytes("New CK", cc->ck, 16);
++}
++
++void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id)
++{
++ dwc_cc_t *cc;
++
++ DWC_DEBUGC("Removing connection context %d", id);
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (!cc) {
++ DWC_ERROR("Uid %d not found in cc list\n", id);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return;
++ }
++
++ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ free_cc(mem_ctx, cc);
++
++ cc_changed(cc_if);
++}
++
++uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length)
++{
++ uint8_t *buf, *x;
++ uint8_t zero = 0;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ *length = cc_data_size(cc_if);
++ if (!(*length)) {
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return NULL;
++ }
++
++ DWC_DEBUGC("Creating data for saving (length=%d)", *length);
++
++ buf = dwc_alloc(mem_ctx, *length);
++ if (!buf) {
++ *length = 0;
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return NULL;
++ }
++
++ x = buf;
++ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) {
++ DWC_MEMCPY(x, cc->chid, 16);
++ x += 16;
++ DWC_MEMCPY(x, cc->cdid, 16);
++ x += 16;
++ DWC_MEMCPY(x, cc->ck, 16);
++ x += 16;
++ if (cc->name) {
++ DWC_MEMCPY(x, &cc->length, 1);
++ x += 1;
++ DWC_MEMCPY(x, cc->name, cc->length);
++ x += cc->length;
++ }
++ else {
++ DWC_MEMCPY(x, &zero, 1);
++ x += 1;
++ }
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return buf;
++}
++
++void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length)
++{
++ uint8_t name_length;
++ uint8_t *name;
++ uint8_t *chid;
++ uint8_t *cdid;
++ uint8_t *ck;
++ uint32_t i = 0;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc_clear(mem_ctx, cc_if);
++
++ while (i < length) {
++ chid = &data[i];
++ i += 16;
++ cdid = &data[i];
++ i += 16;
++ ck = &data[i];
++ i += 16;
++
++ name_length = data[i];
++ i ++;
++
++ if (name_length) {
++ name = &data[i];
++ i += name_length;
++ }
++ else {
++ name = NULL;
++ }
++
++ /* check to see if we haven't overflown the buffer */
++ if (i > length) {
++ DWC_ERROR("Data format error while attempting to load CCs "
++ "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length);
++ break;
++ }
++
++ cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length);
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ cc_changed(cc_if);
++}
++
++uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid)
++{
++ uint32_t uid = 0;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ uid = cc_match_chid(cc_if, chid);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return uid;
++}
++uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid)
++{
++ uint32_t uid = 0;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ uid = cc_match_cdid(cc_if, cdid);
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++ return uid;
++}
++
++uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id)
++{
++ uint8_t *ck = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ ck = cc->ck;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return ck;
++
++}
++
++uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id)
++{
++ uint8_t *retval = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ retval = cc->chid;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return retval;
++}
++
++uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id)
++{
++ uint8_t *retval = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ retval = cc->cdid;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return retval;
++}
++
++uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
++{
++ uint8_t *retval = NULL;
++ dwc_cc_t *cc;
++
++ DWC_MUTEX_LOCK(cc_if->mutex);
++ *length = 0;
++ cc = cc_find(cc_if, id);
++ if (cc) {
++ *length = cc->length;
++ retval = cc->name;
++ }
++ DWC_MUTEX_UNLOCK(cc_if->mutex);
++
++ return retval;
++}
++
++#endif /* DWC_CCLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.h b/drivers/usb/host/dwc_common_port/dwc_cc.h
+new file mode 100644
+index 000000000000..f86e6f21792b
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_cc.h
+@@ -0,0 +1,224 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $
++ * $Revision: #4 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifndef _DWC_CC_H_
++#define _DWC_CC_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file defines the Context Context library.
++ *
++ * The main data structure is dwc_cc_if_t which is returned by either the
++ * dwc_cc_if_alloc function or returned by the module to the user via a provided
++ * function. The data structure is opaque and should only be manipulated via the
++ * functions provied in this API.
++ *
++ * It manages a list of connection contexts and operations can be performed to
++ * add, remove, query, search, and change, those contexts. Additionally,
++ * a dwc_notifier_t object can be requested from the manager so that
++ * the user can be notified whenever the context list has changed.
++ */
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++#include "dwc_notifier.h"
++
++
++/* Notifications */
++#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION"
++
++struct dwc_cc_if;
++typedef struct dwc_cc_if dwc_cc_if_t;
++
++
++/** @name Connection Context Operations */
++/** @{ */
++
++/** This function allocates memory for a dwc_cc_if_t structure, initializes
++ * fields to default values, and returns a pointer to the structure or NULL on
++ * error. */
++extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx,
++ dwc_notifier_t *notifier, unsigned is_host);
++
++/** Frees the memory for the specified CC structure allocated from
++ * dwc_cc_if_alloc(). */
++extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if);
++
++/** Removes all contexts from the connection context list */
++extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if);
++
++/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
++ * If a CHID already exists, the CK and name are overwritten. Statistics are
++ * not overwritten.
++ *
++ * @param cc_if The cc_if structure.
++ * @param chid A pointer to the 16-byte CHID. This value will be copied.
++ * @param ck A pointer to the 16-byte CK. This value will be copied.
++ * @param cdid A pointer to the 16-byte CDID. This value will be copied.
++ * @param name An optional host friendly name as defined in the association model
++ * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
++ * @param length The length othe unicode string.
++ * @return A unique identifier used to refer to this context that is valid for
++ * as long as this context is still in the list. */
++extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid,
++ uint8_t *cdid, uint8_t *ck, uint8_t *name,
++ uint8_t length);
++
++/** Changes the CHID, CK, CDID, or Name values of a connection context in the
++ * list, preserving any accumulated statistics. This would typically be called
++ * if the host decideds to change the context with a SET_CONNECTION request.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL
++ * indicates no change.
++ * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL
++ * indicates no change.
++ * @param ck A pointer to the 16-byte CK. This value will be copied. NULL
++ * indicates no change.
++ * @param name Host friendly name UTF16-LE. NULL indicates no change.
++ * @param length Length of name. */
++extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id,
++ uint8_t *chid, uint8_t *cdid, uint8_t *ck,
++ uint8_t *name, uint8_t length);
++
++/** Remove the specified connection context.
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context to remove. */
++extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id);
++
++/** Get a binary block of data for the connection context list and attributes.
++ * This data can be used by the OS specific driver to save the connection
++ * context list into non-volatile memory.
++ *
++ * @param cc_if The cc_if structure.
++ * @param length Return the length of the data buffer.
++ * @return A pointer to the data buffer. The memory for this buffer should be
++ * freed with DWC_FREE() after use. */
++extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if,
++ unsigned int *length);
++
++/** Restore the connection context list from the binary data that was previously
++ * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific
++ * driver to load a connection context list from non-volatile memory.
++ *
++ * @param cc_if The cc_if structure.
++ * @param data The data bytes as returned from dwc_cc_data_for_save.
++ * @param length The length of the data. */
++extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if,
++ uint8_t *data, unsigned int length);
++
++/** Find the connection context from the specified CHID.
++ *
++ * @param cc_if The cc_if structure.
++ * @param chid A pointer to the CHID data.
++ * @return A non-zero identifier of the connection context if the CHID matches.
++ * Otherwise returns 0. */
++extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid);
++
++/** Find the connection context from the specified CDID.
++ *
++ * @param cc_if The cc_if structure.
++ * @param cdid A pointer to the CDID data.
++ * @return A non-zero identifier of the connection context if the CHID matches.
++ * Otherwise returns 0. */
++extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid);
++
++/** Retrieve the CK from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CK data. The memory does not need to be freed. */
++extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id);
++
++/** Retrieve the CHID from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CHID data. The memory does not need to be freed. */
++extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id);
++
++/** Retrieve the CDID from the specified connection context.
++ *
++ * @param cc_if The cc_if structure.
++ * @param id The identifier of the connection context.
++ * @return A pointer to the CDID data. The memory does not need to be freed. */
++extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id);
++
++extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length);
++
++/** Checks a buffer for non-zero.
++ * @param id A pointer to a 16 byte buffer.
++ * @return true if the 16 byte value is non-zero. */
++static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) {
++ int i;
++ for (i=0; i<16; i++) {
++ if (id[i]) return 1;
++ }
++ return 0;
++}
++
++/** Checks a buffer for zero.
++ * @param id A pointer to a 16 byte buffer.
++ * @return true if the 16 byte value is zero. */
++static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) {
++ return !dwc_assoc_is_not_zero_id(id);
++}
++
++/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into
++ * buffer. */
++static inline int dwc_print_id_string(char *buffer, uint8_t *id) {
++ char *ptr = buffer;
++ int i;
++ for (i=0; i<16; i++) {
++ ptr += DWC_SPRINTF(ptr, "%02x", id[i]);
++ if (i < 15) {
++ ptr += DWC_SPRINTF(ptr, " ");
++ }
++ }
++ return ptr - buffer;
++}
++
++/** @} */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_CC_H_ */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
+new file mode 100644
+index 000000000000..6dd04b58f8f6
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c
+@@ -0,0 +1,1308 @@
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++#ifdef DWC_CCLIB
++# include "dwc_cc.h"
++#endif
++
++#ifdef DWC_CRYPTOLIB
++# include "dwc_modpow.h"
++# include "dwc_dh.h"
++# include "dwc_crypto.h"
++#endif
++
++#ifdef DWC_NOTIFYLIB
++# include "dwc_notifier.h"
++#endif
++
++/* OS-Level Implementations */
++
++/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */
++
++
++/* MISC */
++
++void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
++{
++ return memset(dest, byte, size);
++}
++
++void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
++{
++ return memcpy(dest, src, size);
++}
++
++void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
++{
++ bcopy(src, dest, size);
++ return dest;
++}
++
++int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
++{
++ return memcmp(m1, m2, size);
++}
++
++int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
++{
++ return strncmp(s1, s2, size);
++}
++
++int DWC_STRCMP(void *s1, void *s2)
++{
++ return strcmp(s1, s2);
++}
++
++int DWC_STRLEN(char const *str)
++{
++ return strlen(str);
++}
++
++char *DWC_STRCPY(char *to, char const *from)
++{
++ return strcpy(to, from);
++}
++
++char *DWC_STRDUP(char const *str)
++{
++ int len = DWC_STRLEN(str) + 1;
++ char *new = DWC_ALLOC_ATOMIC(len);
++
++ if (!new) {
++ return NULL;
++ }
++
++ DWC_MEMCPY(new, str, len);
++ return new;
++}
++
++int DWC_ATOI(char *str, int32_t *value)
++{
++ char *end = NULL;
++
++ *value = strtol(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++int DWC_ATOUI(char *str, uint32_t *value)
++{
++ char *end = NULL;
++
++ *value = strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++
++#ifdef DWC_UTFLIB
++/* From usbstring.c */
++
++int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
++{
++ int count = 0;
++ u8 c;
++ u16 uchar;
++
++ /* this insists on correct encodings, though not minimal ones.
++ * BUT it currently rejects legit 4-byte UTF-8 code points,
++ * which need surrogate pairs. (Unicode 3.1 can use them.)
++ */
++ while (len != 0 && (c = (u8) *s++) != 0) {
++ if (unlikely(c & 0x80)) {
++ // 2-byte sequence:
++ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++ if ((c & 0xe0) == 0xc0) {
++ uchar = (c & 0x1f) << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ // 3-byte sequence (most CJKV characters):
++ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++ } else if ((c & 0xf0) == 0xe0) {
++ uchar = (c & 0x0f) << 12;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ /* no bogus surrogates */
++ if (0xd800 <= uchar && uchar <= 0xdfff)
++ goto fail;
++
++ // 4-byte sequence (surrogate pairs, currently rare):
++ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++ // (uuuuu = wwww + 1)
++ // FIXME accept the surrogate code points (only)
++ } else
++ goto fail;
++ } else
++ uchar = c;
++ put_unaligned (cpu_to_le16 (uchar), cp++);
++ count++;
++ len--;
++ }
++ return count;
++fail:
++ return -1;
++}
++
++#endif /* DWC_UTFLIB */
++
++
++/* dwc_debug.h */
++
++dwc_bool_t DWC_IN_IRQ(void)
++{
++// return in_irq();
++ return 0;
++}
++
++dwc_bool_t DWC_IN_BH(void)
++{
++// return in_softirq();
++ return 0;
++}
++
++void DWC_VPRINTF(char *format, va_list args)
++{
++ vprintf(format, args);
++}
++
++int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
++{
++ return vsnprintf(str, size, format, args);
++}
++
++void DWC_PRINTF(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++int DWC_SPRINTF(char *buffer, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsprintf(buffer, format, args);
++ va_end(args);
++ return retval;
++}
++
++int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsnprintf(buffer, size, format, args);
++ va_end(args);
++ return retval;
++}
++
++void __DWC_WARN(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void __DWC_ERROR(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void DWC_EXCEPTION(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++// BUG_ON(1); ???
++}
++
++#ifdef DEBUG
++void __DWC_DEBUG(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++#endif
++
++
++/* dwc_mem.h */
++
++#if 0
++dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
++ uint32_t align,
++ uint32_t alloc)
++{
++ struct dma_pool *pool = dma_pool_create("Pool", NULL,
++ size, align, alloc);
++ return (dwc_pool_t *)pool;
++}
++
++void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
++{
++ dma_pool_destroy((struct dma_pool *)pool);
++}
++
++void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
++ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
++}
++
++void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
++ memset(..);
++}
++
++void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
++{
++ dma_pool_free(pool, vaddr, daddr);
++}
++#endif
++
++static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
++{
++ if (error)
++ return;
++ *(bus_addr_t *)arg = segs[0].ds_addr;
++}
++
++void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++ int error;
++
++ error = bus_dma_tag_create(
++#if __FreeBSD_version >= 700000
++ bus_get_dma_tag(dma->dev), /* parent */
++#else
++ NULL, /* parent */
++#endif
++ 4, 0, /* alignment, bounds */
++ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
++ BUS_SPACE_MAXADDR, /* highaddr */
++ NULL, NULL, /* filter, filterarg */
++ size, /* maxsize */
++ 1, /* nsegments */
++ size, /* maxsegsize */
++ 0, /* flags */
++ NULL, /* lockfunc */
++ NULL, /* lockarg */
++ &dma->dma_tag);
++ if (error) {
++ device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n",
++ __func__, error);
++ goto fail_0;
++ }
++
++ error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr,
++ BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
++ if (error) {
++ device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
++ __func__, (uintmax_t)size, error);
++ goto fail_1;
++ }
++
++ dma->dma_paddr = 0;
++ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size,
++ dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT);
++ if (error || dma->dma_paddr == 0) {
++ device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n",
++ __func__, error);
++ goto fail_2;
++ }
++
++ *dma_addr = dma->dma_paddr;
++ return dma->dma_vaddr;
++
++fail_2:
++ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
++fail_1:
++ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
++ bus_dma_tag_destroy(dma->dma_tag);
++fail_0:
++ dma->dma_map = NULL;
++ dma->dma_tag = NULL;
++
++ return NULL;
++}
++
++void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++
++ if (dma->dma_tag == NULL)
++ return;
++ if (dma->dma_map != NULL) {
++ bus_dmamap_sync(dma->dma_tag, dma->dma_map,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
++ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
++ dma->dma_map = NULL;
++ }
++
++ bus_dma_tag_destroy(dma->dma_tag);
++ dma->dma_tag = NULL;
++}
++
++void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
++}
++
++void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
++}
++
++void __DWC_FREE(void *mem_ctx, void *addr)
++{
++ free(addr, M_DEVBUF);
++}
++
++
++#ifdef DWC_CRYPTOLIB
++/* dwc_crypto.h */
++
++void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
++{
++ get_random_bytes(buffer, length);
++}
++
++int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
++{
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
++ struct scatterlist sgd;
++ struct scatterlist sgs;
++
++ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
++ if (tfm == NULL) {
++ printk("failed to load transform for aes CBC\n");
++ return -1;
++ }
++
++ crypto_blkcipher_setkey(tfm, key, keylen);
++ crypto_blkcipher_set_iv(tfm, iv, 16);
++
++ sg_init_one(&sgd, out, messagelen);
++ sg_init_one(&sgs, message, messagelen);
++
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
++ crypto_free_blkcipher(tfm);
++ DWC_ERROR("AES CBC encryption failed");
++ return -1;
++ }
++
++ crypto_free_blkcipher(tfm);
++ return 0;
++}
++
++int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, len);
++ crypto_hash_digest(&desc, &sg, len, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
++ uint8_t *key, uint32_t keylen, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, messagelen);
++ crypto_hash_setkey(tfm, key, keylen);
++ crypto_hash_digest(&desc, &sg, messagelen, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++#endif /* DWC_CRYPTOLIB */
++
++
++/* Byte Ordering Conversions */
++
++uint32_t DWC_CPU_TO_LE32(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_CPU_TO_BE32(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_LE32_TO_CPU(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_BE32_TO_CPU(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++++
++uint16_t DWC_CPU_TO_LE16(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_CPU_TO_BE16(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_LE16_TO_CPU(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_BE16_TO_CPU(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++
++/* Registers */
++
++uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_4(io->iot, io->ioh, ior);
++}
++
++#if 0
++uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_8(io->iot, io->ioh, ior);
++}
++#endif
++
++void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior, value);
++}
++
++#if 0
++void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior, value);
++}
++#endif
++
++void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
++ uint32_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior,
++ (bus_space_read_4(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++
++#if 0
++void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
++ uint64_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior,
++ (bus_space_read_8(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++#endif
++
++
++/* Locking */
++
++dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
++{
++ struct mtx *sl = DWC_ALLOC(sizeof(*sl));
++
++ if (!sl) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ return NULL;
++ }
++
++ mtx_init(sl, "dw3spn", NULL, MTX_SPIN);
++ return (dwc_spinlock_t *)sl;
++}
++
++void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
++{
++ struct mtx *sl = (struct mtx *)lock;
++
++ mtx_destroy(sl);
++ DWC_FREE(sl);
++}
++
++void DWC_SPINLOCK(dwc_spinlock_t *lock)
++{
++ mtx_lock_spin((struct mtx *)lock); // ???
++}
++
++void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
++{
++ mtx_unlock_spin((struct mtx *)lock); // ???
++}
++
++void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
++{
++ mtx_lock_spin((struct mtx *)lock);
++}
++
++void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
++{
++ mtx_unlock_spin((struct mtx *)lock);
++}
++
++dwc_mutex_t *DWC_MUTEX_ALLOC(void)
++{
++ struct mtx *m;
++ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx));
++
++ if (!mutex) {
++ DWC_ERROR("Cannot allocate memory for mutex");
++ return NULL;
++ }
++
++ m = (struct mtx *)mutex;
++ mtx_init(m, "dw3mtx", NULL, MTX_DEF);
++ return mutex;
++}
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++#else
++void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
++{
++ mtx_destroy((struct mtx *)mutex);
++ DWC_FREE(mutex);
++}
++#endif
++
++void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
++{
++ struct mtx *m = (struct mtx *)mutex;
++
++ mtx_lock(m);
++}
++
++int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
++{
++ struct mtx *m = (struct mtx *)mutex;
++
++ return mtx_trylock(m);
++}
++
++void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
++{
++ struct mtx *m = (struct mtx *)mutex;
++
++ mtx_unlock(m);
++}
++
++
++/* Timing */
++
++void DWC_UDELAY(uint32_t usecs)
++{
++ DELAY(usecs);
++}
++
++void DWC_MDELAY(uint32_t msecs)
++{
++ do {
++ DELAY(1000);
++ } while (--msecs);
++}
++
++void DWC_MSLEEP(uint32_t msecs)
++{
++ struct timeval tv;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++ pause("dw3slp", tvtohz(&tv));
++}
++
++uint32_t DWC_TIME(void)
++{
++ struct timeval tv;
++
++ microuptime(&tv); // or getmicrouptime? (less precise, but faster)
++ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
++}
++
++
++/* Timers */
++
++struct dwc_timer {
++ struct callout t;
++ char *name;
++ dwc_spinlock_t *lock;
++ dwc_timer_callback_t cb;
++ void *data;
++};
++
++dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
++{
++ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (!t) {
++ DWC_ERROR("Cannot allocate memory for timer");
++ return NULL;
++ }
++
++ callout_init(&t->t, 1);
++
++ t->name = DWC_STRDUP(name);
++ if (!t->name) {
++ DWC_ERROR("Cannot allocate memory for timer->name");
++ goto no_name;
++ }
++
++ t->lock = DWC_SPINLOCK_ALLOC();
++ if (!t->lock) {
++ DWC_ERROR("Cannot allocate memory for lock");
++ goto no_lock;
++ }
++
++ t->cb = cb;
++ t->data = data;
++
++ return t;
++
++ no_lock:
++ DWC_FREE(t->name);
++ no_name:
++ DWC_FREE(t);
++
++ return NULL;
++}
++
++void DWC_TIMER_FREE(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++ DWC_SPINLOCK_FREE(timer->lock);
++ DWC_FREE(timer->name);
++ DWC_FREE(timer);
++}
++
++void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
++{
++ struct timeval tv;
++
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
++}
++
++void DWC_TIMER_CANCEL(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++}
++
++
++/* Wait Queues */
++
++struct dwc_waitq {
++ struct mtx lock;
++ int abort;
++};
++
++dwc_waitq_t *DWC_WAITQ_ALLOC(void)
++{
++ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ return NULL;
++ }
++
++ mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF);
++ wq->abort = 0;
++
++ return wq;
++}
++
++void DWC_WAITQ_FREE(dwc_waitq_t *wq)
++{
++ mtx_destroy(&wq->lock);
++ DWC_FREE(wq);
++}
++
++int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
++{
++// intrmask_t ipl;
++ int result = 0;
++
++ mtx_lock(&wq->lock);
++// ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++// splx(ipl);
++ result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout
++// ipl = splbio();
++ }
++
++ if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++
++ } else if (result == EINTR) { // signaled - interrupt
++ result = -DWC_E_ABORT;
++
++ } else if (wq->abort) {
++ result = -DWC_E_ABORT;
++
++ } else {
++ result = 0;
++ }
++
++ wq->abort = 0;
++// splx(ipl);
++ mtx_unlock(&wq->lock);
++ return result;
++}
++
++int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++ void *data, int32_t msecs)
++{
++ struct timeval tv, tv1, tv2;
++// intrmask_t ipl;
++ int result = 0;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++
++ mtx_lock(&wq->lock);
++// ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++// splx(ipl);
++ getmicrouptime(&tv1);
++ result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv));
++ getmicrouptime(&tv2);
++// ipl = splbio();
++ }
++
++ if (result == 0) { // awoken
++ if (wq->abort) {
++ result = -DWC_E_ABORT;
++ } else {
++ tv2.tv_usec -= tv1.tv_usec;
++ if (tv2.tv_usec < 0) {
++ tv2.tv_usec += 1000000;
++ tv2.tv_sec--;
++ }
++
++ tv2.tv_sec -= tv1.tv_sec;
++ result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
++ result = msecs - result;
++ if (result <= 0)
++ result = 1;
++ }
++ } else if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++
++ } else if (result == EINTR) { // signaled - interrupt
++ result = -DWC_E_ABORT;
++
++ } else { // timed out
++ result = -DWC_E_TIMEOUT;
++ }
++
++ wq->abort = 0;
++// splx(ipl);
++ mtx_unlock(&wq->lock);
++ return result;
++}
++
++void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
++{
++ wakeup(wq);
++}
++
++void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
++{
++// intrmask_t ipl;
++
++ mtx_lock(&wq->lock);
++// ipl = splbio();
++ wq->abort = 1;
++ wakeup(wq);
++// splx(ipl);
++ mtx_unlock(&wq->lock);
++}
++
++
++/* Threading */
++
++struct dwc_thread {
++ struct proc *proc;
++ int abort;
++};
++
++dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
++{
++ int retval;
++ dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
++
++ if (!thread) {
++ return NULL;
++ }
++
++ thread->abort = 0;
++ retval = kthread_create((void (*)(void *))func, data, &thread->proc,
++ RFPROC | RFNOWAIT, 0, "%s", name);
++ if (retval) {
++ DWC_FREE(thread);
++ return NULL;
++ }
++
++ return thread;
++}
++
++int DWC_THREAD_STOP(dwc_thread_t *thread)
++{
++ int retval;
++
++ thread->abort = 1;
++ retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
++
++ if (retval == 0) {
++ /* DWC_THREAD_EXIT() will free the thread struct */
++ return 0;
++ }
++
++ /* NOTE: We leak the thread struct if thread doesn't die */
++
++ if (retval == EWOULDBLOCK) {
++ return -DWC_E_TIMEOUT;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
++{
++ return thread->abort;
++}
++
++void DWC_THREAD_EXIT(dwc_thread_t *thread)
++{
++ wakeup(&thread->abort);
++ DWC_FREE(thread);
++ kthread_exit(0);
++}
++
++
++/* tasklets
++ - Runs in interrupt context (cannot sleep)
++ - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ]
++ - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ]
++ */
++struct dwc_tasklet {
++ struct task t;
++ dwc_tasklet_callback_t cb;
++ void *data;
++};
++
++static void tasklet_callback(void *data, int pending) // what to do with pending ???
++{
++ dwc_tasklet_t *task = (dwc_tasklet_t *)data;
++
++ task->cb(task->data);
++}
++
++dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
++{
++ dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
++
++ if (task) {
++ task->cb = cb;
++ task->data = data;
++ TASK_INIT(&task->t, 0, tasklet_callback, task);
++ } else {
++ DWC_ERROR("Cannot allocate memory for tasklet");
++ }
++
++ return task;
++}
++
++void DWC_TASK_FREE(dwc_tasklet_t *task)
++{
++ taskqueue_drain(taskqueue_fast, &task->t); // ???
++ DWC_FREE(task);
++}
++
++void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
++{
++ /* Uses predefined system queue */
++ taskqueue_enqueue_fast(taskqueue_fast, &task->t);
++}
++
++
++/* workqueues
++ - Runs in process context (can sleep)
++ */
++typedef struct work_container {
++ dwc_work_callback_t cb;
++ void *data;
++ dwc_workq_t *wq;
++ char *name;
++ int hz;
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_ENTRY(work_container) entry;
++#endif
++ struct task task;
++} work_container_t;
++
++#ifdef DEBUG
++DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
++#endif
++
++struct dwc_workq {
++ struct taskqueue *taskq;
++ dwc_spinlock_t *lock;
++ dwc_waitq_t *waitq;
++ int pending;
++
++#ifdef DEBUG
++ struct work_container_queue entries;
++#endif
++};
++
++static void do_work(void *data, int pending) // what to do with pending ???
++{
++ work_container_t *container = (work_container_t *)data;
++ dwc_workq_t *wq = container->wq;
++ dwc_irqflags_t flags;
++
++ if (container->hz) {
++ pause("dw3wrk", container->hz);
++ }
++
++ container->cb(container->data);
++ DWC_DEBUG("Work done: %s, container=%p", container->name, container);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
++#endif
++ if (container->name)
++ DWC_FREE(container->name);
++ DWC_FREE(container);
++ wq->pending--;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++}
++
++static int work_done(void *data)
++{
++ dwc_workq_t *workq = (dwc_workq_t *)data;
++
++ return workq->pending == 0;
++}
++
++int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
++{
++ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
++}
++
++dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
++{
++ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for workqueue");
++ return NULL;
++ }
++
++ wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq);
++ if (!wq->taskq) {
++ DWC_ERROR("Cannot allocate memory for taskqueue");
++ goto no_taskq;
++ }
++
++ wq->pending = 0;
++
++ wq->lock = DWC_SPINLOCK_ALLOC();
++ if (!wq->lock) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ goto no_lock;
++ }
++
++ wq->waitq = DWC_WAITQ_ALLOC();
++ if (!wq->waitq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ goto no_waitq;
++ }
++
++ taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk");
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INIT(&wq->entries);
++#endif
++ return wq;
++
++ no_waitq:
++ DWC_SPINLOCK_FREE(wq->lock);
++ no_lock:
++ taskqueue_free(wq->taskq);
++ no_taskq:
++ DWC_FREE(wq);
++
++ return NULL;
++}
++
++void DWC_WORKQ_FREE(dwc_workq_t *wq)
++{
++#ifdef DEBUG
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++
++ if (wq->pending != 0) {
++ struct work_container *container;
++
++ DWC_ERROR("Destroying work queue with pending work");
++
++ DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) {
++ DWC_ERROR("Work %s still pending", container->name);
++ }
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++#endif
++ DWC_WAITQ_FREE(wq->waitq);
++ DWC_SPINLOCK_FREE(wq->lock);
++ taskqueue_free(wq->taskq);
++ DWC_FREE(wq);
++}
++
++void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
++ char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ container->hz = 0;
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++
++ TASK_INIT(&container->task, 0, do_work, container);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++ taskqueue_enqueue_fast(wq->taskq, &container->task);
++}
++
++void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
++ void *data, uint32_t time, char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ struct timeval tv;
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ container->hz = tvtohz(&tv);
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++++
++ TASK_INIT(&container->task, 0, do_work, container);
++++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq-wq->entries, container, entry);
++#endif
++ taskqueue_enqueue_fast(wq->taskq, &container->task);
++}++}
++++
++int DWC_WORKQ_PENDING(dwc_workq_t *wq)
++{
++ return wq->pending;
++}
+diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
+new file mode 100644
+index 000000000000..1460afaf997d
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
+@@ -0,0 +1,1409 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++
++#ifdef DWC_CCLIB
++# include "dwc_cc.h"
++#endif
++
++#ifdef DWC_CRYPTOLIB
++# include "dwc_modpow.h"
++# include "dwc_dh.h"
++# include "dwc_crypto.h"
++#endif
++
++#ifdef DWC_NOTIFYLIB
++# include "dwc_notifier.h"
++#endif
++
++/* OS-Level Implementations */
++
++/* This is the Linux kernel implementation of the DWC platform library. */
++#include <linux/moduleparam.h>
++#include <linux/ctype.h>
++#include <linux/crypto.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/cdev.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/jiffies.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/random.h>
++#include <linux/scatterlist.h>
++#include <linux/slab.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/timer.h>
++#include <linux/usb.h>
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++# include <linux/usb/gadget.h>
++#else
++# include <linux/usb_gadget.h>
++#endif
++
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++
++/* MISC */
++
++void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
++{
++ return memset(dest, byte, size);
++}
++
++void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
++{
++ return memcpy(dest, src, size);
++}
++
++void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
++{
++ return memmove(dest, src, size);
++}
++
++int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
++{
++ return memcmp(m1, m2, size);
++}
++
++int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
++{
++ return strncmp(s1, s2, size);
++}
++
++int DWC_STRCMP(void *s1, void *s2)
++{
++ return strcmp(s1, s2);
++}
++
++int DWC_STRLEN(char const *str)
++{
++ return strlen(str);
++}
++
++char *DWC_STRCPY(char *to, char const *from)
++{
++ return strcpy(to, from);
++}
++
++char *DWC_STRDUP(char const *str)
++{
++ int len = DWC_STRLEN(str) + 1;
++ char *new = DWC_ALLOC_ATOMIC(len);
++
++ if (!new) {
++ return NULL;
++ }
++
++ DWC_MEMCPY(new, str, len);
++ return new;
++}
++
++int DWC_ATOI(const char *str, int32_t *value)
++{
++ char *end = NULL;
++
++ *value = simple_strtol(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++int DWC_ATOUI(const char *str, uint32_t *value)
++{
++ char *end = NULL;
++
++ *value = simple_strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++
++ return -1;
++}
++
++
++#ifdef DWC_UTFLIB
++/* From usbstring.c */
++
++int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
++{
++ int count = 0;
++ u8 c;
++ u16 uchar;
++
++ /* this insists on correct encodings, though not minimal ones.
++ * BUT it currently rejects legit 4-byte UTF-8 code points,
++ * which need surrogate pairs. (Unicode 3.1 can use them.)
++ */
++ while (len != 0 && (c = (u8) *s++) != 0) {
++ if (unlikely(c & 0x80)) {
++ // 2-byte sequence:
++ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++ if ((c & 0xe0) == 0xc0) {
++ uchar = (c & 0x1f) << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ // 3-byte sequence (most CJKV characters):
++ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++ } else if ((c & 0xf0) == 0xe0) {
++ uchar = (c & 0x0f) << 12;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ /* no bogus surrogates */
++ if (0xd800 <= uchar && uchar <= 0xdfff)
++ goto fail;
++
++ // 4-byte sequence (surrogate pairs, currently rare):
++ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++ // (uuuuu = wwww + 1)
++ // FIXME accept the surrogate code points (only)
++ } else
++ goto fail;
++ } else
++ uchar = c;
++ put_unaligned (cpu_to_le16 (uchar), cp++);
++ count++;
++ len--;
++ }
++ return count;
++fail:
++ return -1;
++}
++#endif /* DWC_UTFLIB */
++
++
++/* dwc_debug.h */
++
++dwc_bool_t DWC_IN_IRQ(void)
++{
++ return in_irq();
++}
++
++dwc_bool_t DWC_IN_BH(void)
++{
++ return in_softirq();
++}
++
++void DWC_VPRINTF(char *format, va_list args)
++{
++ vprintk(format, args);
++}
++
++int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
++{
++ return vsnprintf(str, size, format, args);
++}
++
++void DWC_PRINTF(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++int DWC_SPRINTF(char *buffer, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsprintf(buffer, format, args);
++ va_end(args);
++ return retval;
++}
++
++int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsnprintf(buffer, size, format, args);
++ va_end(args);
++ return retval;
++}
++
++void __DWC_WARN(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_WARNING);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void __DWC_ERROR(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_ERR);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void DWC_EXCEPTION(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_ERR);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++ BUG_ON(1);
++}
++
++#ifdef DEBUG
++void __DWC_DEBUG(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_PRINTF(KERN_DEBUG);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++#endif
++
++
++/* dwc_mem.h */
++
++#if 0
++dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
++ uint32_t align,
++ uint32_t alloc)
++{
++ struct dma_pool *pool = dma_pool_create("Pool", NULL,
++ size, align, alloc);
++ return (dwc_pool_t *)pool;
++}
++
++void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
++{
++ dma_pool_destroy((struct dma_pool *)pool);
++}
++
++void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
++}
++
++void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
++ memset(..);
++}
++
++void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
++{
++ dma_pool_free(pool, vaddr, daddr);
++}
++#endif
++
++void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ return dma_alloc_coherent(dma_ctx, size, dma_addr, GFP_KERNEL | GFP_DMA32);
++}
++
++void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ return dma_alloc_coherent(dma_ctx, size, dma_addr, GFP_ATOMIC);
++}
++
++void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
++{
++ dma_free_coherent(dma_ctx, size, virt_addr, dma_addr);
++}
++
++void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
++{
++ return kzalloc(size, GFP_KERNEL);
++}
++
++void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
++{
++ return kzalloc(size, GFP_ATOMIC);
++}
++
++void __DWC_FREE(void *mem_ctx, void *addr)
++{
++ kfree(addr);
++}
++
++
++#ifdef DWC_CRYPTOLIB
++/* dwc_crypto.h */
++
++void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
++{
++ get_random_bytes(buffer, length);
++}
++
++int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
++{
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
++ struct scatterlist sgd;
++ struct scatterlist sgs;
++
++ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
++ if (tfm == NULL) {
++ printk("failed to load transform for aes CBC\n");
++ return -1;
++ }
++
++ crypto_blkcipher_setkey(tfm, key, keylen);
++ crypto_blkcipher_set_iv(tfm, iv, 16);
++
++ sg_init_one(&sgd, out, messagelen);
++ sg_init_one(&sgs, message, messagelen);
++
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
++ crypto_free_blkcipher(tfm);
++ DWC_ERROR("AES CBC encryption failed");
++ return -1;
++ }
++
++ crypto_free_blkcipher(tfm);
++ return 0;
++}
++
++int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, len);
++ crypto_hash_digest(&desc, &sg, len, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
++ uint8_t *key, uint32_t keylen, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, messagelen);
++ crypto_hash_setkey(tfm, key, keylen);
++ crypto_hash_digest(&desc, &sg, messagelen, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++#endif /* DWC_CRYPTOLIB */
++
++
++/* Byte Ordering Conversions */
++
++uint32_t DWC_CPU_TO_LE32(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_CPU_TO_BE32(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_LE32_TO_CPU(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_BE32_TO_CPU(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint16_t DWC_CPU_TO_LE16(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_CPU_TO_BE16(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_LE16_TO_CPU(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_BE16_TO_CPU(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++
++/* Registers */
++
++uint32_t DWC_READ_REG32(uint32_t volatile *reg)
++{
++ return readl(reg);
++}
++
++#if 0
++uint64_t DWC_READ_REG64(uint64_t volatile *reg)
++{
++}
++#endif
++
++void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value)
++{
++ writel(value, reg);
++}
++
++#if 0
++void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
++{
++}
++#endif
++
++void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
++{
++ writel((readl(reg) & ~clear_mask) | set_mask, reg);
++}
++
++#if 0
++void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask)
++{
++}
++#endif
++
++
++/* Locking */
++
++dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
++{
++ spinlock_t *sl = (spinlock_t *)1;
++
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ sl = DWC_ALLOC(sizeof(*sl));
++ if (!sl) {
++ DWC_ERROR("Cannot allocate memory for spinlock\n");
++ return NULL;
++ }
++
++ spin_lock_init(sl);
++#endif
++ return (dwc_spinlock_t *)sl;
++}
++
++void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ DWC_FREE(lock);
++#endif
++}
++
++void DWC_SPINLOCK(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_lock((spinlock_t *)lock);
++#endif
++}
++
++void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_unlock((spinlock_t *)lock);
++#endif
++}
++
++void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
++{
++ dwc_irqflags_t f;
++
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_lock_irqsave((spinlock_t *)lock, f);
++#else
++ local_irq_save(f);
++#endif
++ *flags = f;
++}
++
++void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
++{
++#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP)
++ spin_unlock_irqrestore((spinlock_t *)lock, flags);
++#else
++ local_irq_restore(flags);
++#endif
++}
++
++dwc_mutex_t *DWC_MUTEX_ALLOC(void)
++{
++ struct mutex *m;
++ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex));
++
++ if (!mutex) {
++ DWC_ERROR("Cannot allocate memory for mutex\n");
++ return NULL;
++ }
++
++ m = (struct mutex *)mutex;
++ mutex_init(m);
++ return mutex;
++}
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++#else
++void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
++{
++ mutex_destroy((struct mutex *)mutex);
++ DWC_FREE(mutex);
++}
++#endif
++
++void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
++{
++ struct mutex *m = (struct mutex *)mutex;
++ mutex_lock(m);
++}
++
++int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
++{
++ struct mutex *m = (struct mutex *)mutex;
++ return mutex_trylock(m);
++}
++
++void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
++{
++ struct mutex *m = (struct mutex *)mutex;
++ mutex_unlock(m);
++}
++
++
++/* Timing */
++
++void DWC_UDELAY(uint32_t usecs)
++{
++ udelay(usecs);
++}
++
++void DWC_MDELAY(uint32_t msecs)
++{
++ mdelay(msecs);
++}
++
++void DWC_MSLEEP(uint32_t msecs)
++{
++ msleep(msecs);
++}
++
++uint32_t DWC_TIME(void)
++{
++ return jiffies_to_msecs(jiffies);
++}
++
++
++/* Timers */
++
++struct dwc_timer {
++ struct timer_list t;
++ char *name;
++ dwc_timer_callback_t cb;
++ void *data;
++ uint8_t scheduled;
++ dwc_spinlock_t *lock;
++};
++
++static void timer_callback(struct timer_list *tt)
++{
++ dwc_timer_t *timer = from_timer(timer, tt, t);
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++ timer->scheduled = 0;
++ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++ DWC_DEBUGC("Timer %s callback", timer->name);
++ timer->cb(timer->data);
++}
++
++dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
++{
++ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (!t) {
++ DWC_ERROR("Cannot allocate memory for timer");
++ return NULL;
++ }
++
++ t->name = DWC_STRDUP(name);
++ if (!t->name) {
++ DWC_ERROR("Cannot allocate memory for timer->name");
++ goto no_name;
++ }
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
++ DWC_SPINLOCK_ALLOC_LINUX_DEBUG(t->lock);
++#else
++ t->lock = DWC_SPINLOCK_ALLOC();
++#endif
++ if (!t->lock) {
++ DWC_ERROR("Cannot allocate memory for lock");
++ goto no_lock;
++ }
++
++ t->scheduled = 0;
++ t->t.expires = jiffies;
++ timer_setup(&t->t, timer_callback, 0);
++
++ t->cb = cb;
++ t->data = data;
++
++ return t;
++
++ no_lock:
++ DWC_FREE(t->name);
++ no_name:
++ DWC_FREE(t);
++ return NULL;
++}
++
++void DWC_TIMER_FREE(dwc_timer_t *timer)
++{
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++
++ if (timer->scheduled) {
++ del_timer(&timer->t);
++ timer->scheduled = 0;
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++ DWC_SPINLOCK_FREE(timer->lock);
++ DWC_FREE(timer->name);
++ DWC_FREE(timer);
++}
++
++void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
++{
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags);
++
++ if (!timer->scheduled) {
++ timer->scheduled = 1;
++ DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time);
++ timer->t.expires = jiffies + msecs_to_jiffies(time);
++ add_timer(&timer->t);
++ } else {
++ DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time);
++ mod_timer(&timer->t, jiffies + msecs_to_jiffies(time));
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags);
++}
++
++void DWC_TIMER_CANCEL(dwc_timer_t *timer)
++{
++ del_timer(&timer->t);
++}
++
++
++/* Wait Queues */
++
++struct dwc_waitq {
++ wait_queue_head_t queue;
++ int abort;
++};
++
++dwc_waitq_t *DWC_WAITQ_ALLOC(void)
++{
++ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue\n");
++ return NULL;
++ }
++
++ init_waitqueue_head(&wq->queue);
++ wq->abort = 0;
++ return wq;
++}
++
++void DWC_WAITQ_FREE(dwc_waitq_t *wq)
++{
++ DWC_FREE(wq);
++}
++
++int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
++{
++ int result = wait_event_interruptible(wq->queue,
++ cond(data) || wq->abort);
++ if (result == -ERESTARTSYS) {
++ wq->abort = 0;
++ return -DWC_E_RESTART;
++ }
++
++ if (wq->abort == 1) {
++ wq->abort = 0;
++ return -DWC_E_ABORT;
++ }
++
++ wq->abort = 0;
++
++ if (result == 0) {
++ return 0;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++ void *data, int32_t msecs)
++{
++ int32_t tmsecs;
++ int result = wait_event_interruptible_timeout(wq->queue,
++ cond(data) || wq->abort,
++ msecs_to_jiffies(msecs));
++ if (result == -ERESTARTSYS) {
++ wq->abort = 0;
++ return -DWC_E_RESTART;
++ }
++
++ if (wq->abort == 1) {
++ wq->abort = 0;
++ return -DWC_E_ABORT;
++ }
++
++ wq->abort = 0;
++
++ if (result > 0) {
++ tmsecs = jiffies_to_msecs(result);
++ if (!tmsecs) {
++ return 1;
++ }
++
++ return tmsecs;
++ }
++
++ if (result == 0) {
++ return -DWC_E_TIMEOUT;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
++{
++ wq->abort = 0;
++ wake_up_interruptible(&wq->queue);
++}
++
++void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
++{
++ wq->abort = 1;
++ wake_up_interruptible(&wq->queue);
++}
++
++
++/* Threading */
++
++dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
++{
++ struct task_struct *thread = kthread_run(func, data, name);
++
++ if (thread == ERR_PTR(-ENOMEM)) {
++ return NULL;
++ }
++
++ return (dwc_thread_t *)thread;
++}
++
++int DWC_THREAD_STOP(dwc_thread_t *thread)
++{
++ return kthread_stop((struct task_struct *)thread);
++}
++
++dwc_bool_t DWC_THREAD_SHOULD_STOP(void)
++{
++ return kthread_should_stop();
++}
++
++
++/* tasklets
++ - run in interrupt context (cannot sleep)
++ - each tasklet runs on a single CPU
++ - different tasklets can be running simultaneously on different CPUs
++ */
++struct dwc_tasklet {
++ struct tasklet_struct t;
++ dwc_tasklet_callback_t cb;
++ void *data;
++};
++
++static void tasklet_callback(unsigned long data)
++{
++ dwc_tasklet_t *t = (dwc_tasklet_t *)data;
++ t->cb(t->data);
++}
++
++dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
++{
++ dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (t) {
++ t->cb = cb;
++ t->data = data;
++ tasklet_init(&t->t, tasklet_callback, (unsigned long)t);
++ } else {
++ DWC_ERROR("Cannot allocate memory for tasklet\n");
++ }
++
++ return t;
++}
++
++void DWC_TASK_FREE(dwc_tasklet_t *task)
++{
++ DWC_FREE(task);
++}
++
++void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
++{
++ tasklet_schedule(&task->t);
++}
++
++void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task)
++{
++ tasklet_hi_schedule(&task->t);
++}
++
++
++/* workqueues
++ - run in process context (can sleep)
++ */
++typedef struct work_container {
++ dwc_work_callback_t cb;
++ void *data;
++ dwc_workq_t *wq;
++ char *name;
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_ENTRY(work_container) entry;
++#endif
++ struct delayed_work work;
++} work_container_t;
++
++#ifdef DEBUG
++DWC_CIRCLEQ_HEAD(work_container_queue, work_container);
++#endif
++
++struct dwc_workq {
++ struct workqueue_struct *wq;
++ dwc_spinlock_t *lock;
++ dwc_waitq_t *waitq;
++ int pending;
++
++#ifdef DEBUG
++ struct work_container_queue entries;
++#endif
++};
++
++static void do_work(struct work_struct *work)
++{
++ dwc_irqflags_t flags;
++ struct delayed_work *dw = container_of(work, struct delayed_work, work);
++ work_container_t *container = container_of(dw, struct work_container, work);
++ dwc_workq_t *wq = container->wq;
++
++ container->cb(container->data);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry);
++#endif
++ DWC_DEBUGC("Work done: %s, container=%p", container->name, container);
++ if (container->name) {
++ DWC_FREE(container->name);
++ }
++ DWC_FREE(container);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending--;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++}
++
++static int work_done(void *data)
++{
++ dwc_workq_t *workq = (dwc_workq_t *)data;
++ return workq->pending == 0;
++}
++
++int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
++{
++ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
++}
++
++dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
++{
++ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ return NULL;
++ }
++
++ wq->wq = create_singlethread_workqueue(name);
++ if (!wq->wq) {
++ goto no_wq;
++ }
++
++ wq->pending = 0;
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK))
++ DWC_SPINLOCK_ALLOC_LINUX_DEBUG(wq->lock);
++#else
++ wq->lock = DWC_SPINLOCK_ALLOC();
++#endif
++ if (!wq->lock) {
++ goto no_lock;
++ }
++
++ wq->waitq = DWC_WAITQ_ALLOC();
++ if (!wq->waitq) {
++ goto no_waitq;
++ }
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INIT(&wq->entries);
++#endif
++ return wq;
++
++ no_waitq:
++ DWC_SPINLOCK_FREE(wq->lock);
++ no_lock:
++ destroy_workqueue(wq->wq);
++ no_wq:
++ DWC_FREE(wq);
++
++ return NULL;
++}
++
++void DWC_WORKQ_FREE(dwc_workq_t *wq)
++{
++#ifdef DEBUG
++ if (wq->pending != 0) {
++ struct work_container *wc;
++ DWC_ERROR("Destroying work queue with pending work");
++ DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) {
++ DWC_ERROR("Work %s still pending", wc->name);
++ }
++ }
++#endif
++ destroy_workqueue(wq->wq);
++ DWC_SPINLOCK_FREE(wq->lock);
++ DWC_WAITQ_FREE(wq->waitq);
++ DWC_FREE(wq);
++}
++
++void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
++ char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container\n");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name\n");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
++ INIT_WORK(&container->work.work, do_work);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++ queue_work(wq->wq, &container->work.work);
++}
++
++void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
++ void *data, uint32_t time, char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container\n");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name\n");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container);
++ INIT_DELAYED_WORK(&container->work, do_work);
++
++#ifdef DEBUG
++ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry);
++#endif
++ queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time));
++}
++
++int DWC_WORKQ_PENDING(dwc_workq_t *wq)
++{
++ return wq->pending;
++}
++
++
++#ifdef DWC_LIBMODULE
++
++#ifdef DWC_CCLIB
++/* CC */
++EXPORT_SYMBOL(dwc_cc_if_alloc);
++EXPORT_SYMBOL(dwc_cc_if_free);
++EXPORT_SYMBOL(dwc_cc_clear);
++EXPORT_SYMBOL(dwc_cc_add);
++EXPORT_SYMBOL(dwc_cc_remove);
++EXPORT_SYMBOL(dwc_cc_change);
++EXPORT_SYMBOL(dwc_cc_data_for_save);
++EXPORT_SYMBOL(dwc_cc_restore_from_data);
++EXPORT_SYMBOL(dwc_cc_match_chid);
++EXPORT_SYMBOL(dwc_cc_match_cdid);
++EXPORT_SYMBOL(dwc_cc_ck);
++EXPORT_SYMBOL(dwc_cc_chid);
++EXPORT_SYMBOL(dwc_cc_cdid);
++EXPORT_SYMBOL(dwc_cc_name);
++#endif /* DWC_CCLIB */
++
++#ifdef DWC_CRYPTOLIB
++# ifndef CONFIG_MACH_IPMATE
++/* Modpow */
++EXPORT_SYMBOL(dwc_modpow);
++
++/* DH */
++EXPORT_SYMBOL(dwc_dh_modpow);
++EXPORT_SYMBOL(dwc_dh_derive_keys);
++EXPORT_SYMBOL(dwc_dh_pk);
++# endif /* CONFIG_MACH_IPMATE */
++
++/* Crypto */
++EXPORT_SYMBOL(dwc_wusb_aes_encrypt);
++EXPORT_SYMBOL(dwc_wusb_cmf);
++EXPORT_SYMBOL(dwc_wusb_prf);
++EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce);
++EXPORT_SYMBOL(dwc_wusb_gen_nonce);
++EXPORT_SYMBOL(dwc_wusb_gen_key);
++EXPORT_SYMBOL(dwc_wusb_gen_mic);
++#endif /* DWC_CRYPTOLIB */
++
++/* Notification */
++#ifdef DWC_NOTIFYLIB
++EXPORT_SYMBOL(dwc_alloc_notification_manager);
++EXPORT_SYMBOL(dwc_free_notification_manager);
++EXPORT_SYMBOL(dwc_register_notifier);
++EXPORT_SYMBOL(dwc_unregister_notifier);
++EXPORT_SYMBOL(dwc_add_observer);
++EXPORT_SYMBOL(dwc_remove_observer);
++EXPORT_SYMBOL(dwc_notify);
++#endif
++
++/* Memory Debugging Routines */
++#ifdef DWC_DEBUG_MEMORY
++EXPORT_SYMBOL(dwc_alloc_debug);
++EXPORT_SYMBOL(dwc_alloc_atomic_debug);
++EXPORT_SYMBOL(dwc_free_debug);
++EXPORT_SYMBOL(dwc_dma_alloc_debug);
++EXPORT_SYMBOL(dwc_dma_free_debug);
++#endif
++
++EXPORT_SYMBOL(DWC_MEMSET);
++EXPORT_SYMBOL(DWC_MEMCPY);
++EXPORT_SYMBOL(DWC_MEMMOVE);
++EXPORT_SYMBOL(DWC_MEMCMP);
++EXPORT_SYMBOL(DWC_STRNCMP);
++EXPORT_SYMBOL(DWC_STRCMP);
++EXPORT_SYMBOL(DWC_STRLEN);
++EXPORT_SYMBOL(DWC_STRCPY);
++EXPORT_SYMBOL(DWC_STRDUP);
++EXPORT_SYMBOL(DWC_ATOI);
++EXPORT_SYMBOL(DWC_ATOUI);
++
++#ifdef DWC_UTFLIB
++EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE);
++#endif /* DWC_UTFLIB */
++
++EXPORT_SYMBOL(DWC_IN_IRQ);
++EXPORT_SYMBOL(DWC_IN_BH);
++EXPORT_SYMBOL(DWC_VPRINTF);
++EXPORT_SYMBOL(DWC_VSNPRINTF);
++EXPORT_SYMBOL(DWC_PRINTF);
++EXPORT_SYMBOL(DWC_SPRINTF);
++EXPORT_SYMBOL(DWC_SNPRINTF);
++EXPORT_SYMBOL(__DWC_WARN);
++EXPORT_SYMBOL(__DWC_ERROR);
++EXPORT_SYMBOL(DWC_EXCEPTION);
++
++#ifdef DEBUG
++EXPORT_SYMBOL(__DWC_DEBUG);
++#endif
++
++EXPORT_SYMBOL(__DWC_DMA_ALLOC);
++EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC);
++EXPORT_SYMBOL(__DWC_DMA_FREE);
++EXPORT_SYMBOL(__DWC_ALLOC);
++EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC);
++EXPORT_SYMBOL(__DWC_FREE);
++
++#ifdef DWC_CRYPTOLIB
++EXPORT_SYMBOL(DWC_RANDOM_BYTES);
++EXPORT_SYMBOL(DWC_AES_CBC);
++EXPORT_SYMBOL(DWC_SHA256);
++EXPORT_SYMBOL(DWC_HMAC_SHA256);
++#endif
++
++EXPORT_SYMBOL(DWC_CPU_TO_LE32);
++EXPORT_SYMBOL(DWC_CPU_TO_BE32);
++EXPORT_SYMBOL(DWC_LE32_TO_CPU);
++EXPORT_SYMBOL(DWC_BE32_TO_CPU);
++EXPORT_SYMBOL(DWC_CPU_TO_LE16);
++EXPORT_SYMBOL(DWC_CPU_TO_BE16);
++EXPORT_SYMBOL(DWC_LE16_TO_CPU);
++EXPORT_SYMBOL(DWC_BE16_TO_CPU);
++EXPORT_SYMBOL(DWC_READ_REG32);
++EXPORT_SYMBOL(DWC_WRITE_REG32);
++EXPORT_SYMBOL(DWC_MODIFY_REG32);
++
++#if 0
++EXPORT_SYMBOL(DWC_READ_REG64);
++EXPORT_SYMBOL(DWC_WRITE_REG64);
++EXPORT_SYMBOL(DWC_MODIFY_REG64);
++#endif
++
++EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC);
++EXPORT_SYMBOL(DWC_SPINLOCK_FREE);
++EXPORT_SYMBOL(DWC_SPINLOCK);
++EXPORT_SYMBOL(DWC_SPINUNLOCK);
++EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE);
++EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE);
++EXPORT_SYMBOL(DWC_MUTEX_ALLOC);
++
++#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES))
++EXPORT_SYMBOL(DWC_MUTEX_FREE);
++#endif
++
++EXPORT_SYMBOL(DWC_MUTEX_LOCK);
++EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK);
++EXPORT_SYMBOL(DWC_MUTEX_UNLOCK);
++EXPORT_SYMBOL(DWC_UDELAY);
++EXPORT_SYMBOL(DWC_MDELAY);
++EXPORT_SYMBOL(DWC_MSLEEP);
++EXPORT_SYMBOL(DWC_TIME);
++EXPORT_SYMBOL(DWC_TIMER_ALLOC);
++EXPORT_SYMBOL(DWC_TIMER_FREE);
++EXPORT_SYMBOL(DWC_TIMER_SCHEDULE);
++EXPORT_SYMBOL(DWC_TIMER_CANCEL);
++EXPORT_SYMBOL(DWC_WAITQ_ALLOC);
++EXPORT_SYMBOL(DWC_WAITQ_FREE);
++EXPORT_SYMBOL(DWC_WAITQ_WAIT);
++EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT);
++EXPORT_SYMBOL(DWC_WAITQ_TRIGGER);
++EXPORT_SYMBOL(DWC_WAITQ_ABORT);
++EXPORT_SYMBOL(DWC_THREAD_RUN);
++EXPORT_SYMBOL(DWC_THREAD_STOP);
++EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP);
++EXPORT_SYMBOL(DWC_TASK_ALLOC);
++EXPORT_SYMBOL(DWC_TASK_FREE);
++EXPORT_SYMBOL(DWC_TASK_SCHEDULE);
++EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE);
++EXPORT_SYMBOL(DWC_WORKQ_ALLOC);
++EXPORT_SYMBOL(DWC_WORKQ_FREE);
++EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE);
++EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED);
++EXPORT_SYMBOL(DWC_WORKQ_PENDING);
++
++static int dwc_common_port_init_module(void)
++{
++ int result = 0;
++
++ printk(KERN_DEBUG "Module dwc_common_port init\n" );
++
++#ifdef DWC_DEBUG_MEMORY
++ result = dwc_memory_debug_start(NULL);
++ if (result) {
++ printk(KERN_ERR
++ "dwc_memory_debug_start() failed with error %d\n",
++ result);
++ return result;
++ }
++#endif
++
++#ifdef DWC_NOTIFYLIB
++ result = dwc_alloc_notification_manager(NULL, NULL);
++ if (result) {
++ printk(KERN_ERR
++ "dwc_alloc_notification_manager() failed with error %d\n",
++ result);
++ return result;
++ }
++#endif
++ return result;
++}
++
++static void dwc_common_port_exit_module(void)
++{
++ printk(KERN_DEBUG "Module dwc_common_port exit\n" );
++
++#ifdef DWC_NOTIFYLIB
++ dwc_free_notification_manager();
++#endif
++
++#ifdef DWC_DEBUG_MEMORY
++ dwc_memory_debug_stop();
++#endif
++}
++
++module_init(dwc_common_port_init_module);
++module_exit(dwc_common_port_exit_module);
++
++MODULE_DESCRIPTION("DWC Common Library - Portable version");
++MODULE_AUTHOR("Synopsys Inc.");
++MODULE_LICENSE ("GPL");
++
++#endif /* DWC_LIBMODULE */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
+new file mode 100644
+index 000000000000..49b07e172264
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c
+@@ -0,0 +1,1275 @@
++#include "dwc_os.h"
++#include "dwc_list.h"
++
++#ifdef DWC_CCLIB
++# include "dwc_cc.h"
++#endif
++
++#ifdef DWC_CRYPTOLIB
++# include "dwc_modpow.h"
++# include "dwc_dh.h"
++# include "dwc_crypto.h"
++#endif
++
++#ifdef DWC_NOTIFYLIB
++# include "dwc_notifier.h"
++#endif
++
++/* OS-Level Implementations */
++
++/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */
++
++
++/* MISC */
++
++void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size)
++{
++ return memset(dest, byte, size);
++}
++
++void *DWC_MEMCPY(void *dest, void const *src, uint32_t size)
++{
++ return memcpy(dest, src, size);
++}
++
++void *DWC_MEMMOVE(void *dest, void *src, uint32_t size)
++{
++ bcopy(src, dest, size);
++ return dest;
++}
++
++int DWC_MEMCMP(void *m1, void *m2, uint32_t size)
++{
++ return memcmp(m1, m2, size);
++}
++
++int DWC_STRNCMP(void *s1, void *s2, uint32_t size)
++{
++ return strncmp(s1, s2, size);
++}
++
++int DWC_STRCMP(void *s1, void *s2)
++{
++ return strcmp(s1, s2);
++}
++
++int DWC_STRLEN(char const *str)
++{
++ return strlen(str);
++}
++
++char *DWC_STRCPY(char *to, char const *from)
++{
++ return strcpy(to, from);
++}
++
++char *DWC_STRDUP(char const *str)
++{
++ int len = DWC_STRLEN(str) + 1;
++ char *new = DWC_ALLOC_ATOMIC(len);
++
++ if (!new) {
++ return NULL;
++ }
++
++ DWC_MEMCPY(new, str, len);
++ return new;
++}++}
++++
++int DWC_ATOI(char *str, int32_t *value)
++{++{
++ char *end = NULL;
++++
++ /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul'
++ * should be equivalent on 2's complement machines
++ */
++ *value = strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++++
++ return -1;
++}
++++
++int DWC_ATOUI(char *str, uint32_t *value)
++{
++ char *end = NULL;
++
++ *value = strtoul(str, &end, 0);
++ if (*end == '\0') {
++ return 0;
++ }
++++
++ return -1;
++}++}
++++
++++
++#ifdef DWC_UTFLIB
++/* From usbstring.c */
++++
++int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len)
++{
++ int count = 0;
++ u8 c;
++ u16 uchar;
++
++ /* this insists on correct encodings, though not minimal ones.
++ * BUT it currently rejects legit 4-byte UTF-8 code points,
++ * which need surrogate pairs. (Unicode 3.1 can use them.)
++ */
++ while (len != 0 && (c = (u8) *s++) != 0) {
++ if (unlikely(c & 0x80)) {
++ // 2-byte sequence:
++ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
++ if ((c & 0xe0) == 0xc0) {
++ uchar = (c & 0x1f) << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ // 3-byte sequence (most CJKV characters):
++ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
++ } else if ((c & 0xf0) == 0xe0) {
++ uchar = (c & 0x0f) << 12;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c << 6;
++
++ c = (u8) *s++;
++ if ((c & 0xc0) != 0xc0)
++ goto fail;
++ c &= 0x3f;
++ uchar |= c;
++
++ /* no bogus surrogates */
++ if (0xd800 <= uchar && uchar <= 0xdfff)
++ goto fail;
++
++ // 4-byte sequence (surrogate pairs, currently rare):
++ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
++ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
++ // (uuuuu = wwww + 1)
++ // FIXME accept the surrogate code points (only)
++ } else
++ goto fail;
++ } else
++ uchar = c;
++ put_unaligned (cpu_to_le16 (uchar), cp++);
++ count++;
++ len--;
++ }
++ return count;
++fail:
++ return -1;
++}
++
++#endif /* DWC_UTFLIB */
++
++
++/* dwc_debug.h */
++
++dwc_bool_t DWC_IN_IRQ(void)
++{
++// return in_irq();
++ return 0;
++}
++
++dwc_bool_t DWC_IN_BH(void)
++{
++// return in_softirq();
++ return 0;
++}
++
++void DWC_VPRINTF(char *format, va_list args)
++{
++ vprintf(format, args);
++}
++
++int DWC_VSNPRINTF(char *str, int size, char *format, va_list args)
++{
++ return vsnprintf(str, size, format, args);
++}
++
++void DWC_PRINTF(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++int DWC_SPRINTF(char *buffer, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsprintf(buffer, format, args);
++ va_end(args);
++ return retval;
++}
++
++int DWC_SNPRINTF(char *buffer, int size, char *format, ...)
++{
++ int retval;
++ va_list args;
++
++ va_start(args, format);
++ retval = vsnprintf(buffer, size, format, args);
++ va_end(args);
++ return retval;
++}
++
++void __DWC_WARN(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void __DWC_ERROR(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++
++void DWC_EXCEPTION(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++// BUG_ON(1); ???
++}
++
++#ifdef DEBUG
++void __DWC_DEBUG(char *format, ...)
++{
++ va_list args;
++
++ va_start(args, format);
++ DWC_VPRINTF(format, args);
++ va_end(args);
++}
++#endif
++
++
++/* dwc_mem.h */
++
++#if 0
++dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size,
++ uint32_t align,
++ uint32_t alloc)
++{
++ struct dma_pool *pool = dma_pool_create("Pool", NULL,
++ size, align, alloc);
++ return (dwc_pool_t *)pool;
++}
++
++void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool)
++{
++ dma_pool_destroy((struct dma_pool *)pool);
++}
++
++void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr);
++ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr);
++}
++
++void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr)
++{
++ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr);
++ memset(..);
++}
++
++void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr)
++{
++ dma_pool_free(pool, vaddr, daddr);
++}
++#endif
++
++void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++ int error;
++
++ error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs,
++ sizeof(dma->segs) / sizeof(dma->segs[0]),
++ &dma->nsegs, BUS_DMA_NOWAIT);
++ if (error) {
++ printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__,
++ (uintmax_t)size, error);
++ goto fail_0;
++ }
++
++ error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size,
++ (caddr_t *)&dma->dma_vaddr,
++ BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
++ if (error) {
++ printf("%s: bus_dmamem_map failed: %d\n", __func__, error);
++ goto fail_1;
++ }
++
++ error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0,
++ BUS_DMA_NOWAIT, &dma->dma_map);
++ if (error) {
++ printf("%s: bus_dmamap_create failed: %d\n", __func__, error);
++ goto fail_2;
++ }
++
++ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr,
++ size, NULL, BUS_DMA_NOWAIT);
++ if (error) {
++ printf("%s: bus_dmamap_load failed: %d\n", __func__, error);
++ goto fail_3;
++ }
++
++ dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr;
++ *dma_addr = dma->dma_paddr;
++ return dma->dma_vaddr;
++
++fail_3:
++ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
++fail_2:
++ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
++fail_1:
++ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
++fail_0:
++ dma->dma_map = NULL;
++ dma->dma_vaddr = NULL;
++ dma->nsegs = 0;
++
++ return NULL;
++}
++
++void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
++{
++ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx;
++
++ if (dma->dma_map != NULL) {
++ bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size,
++ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
++ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
++ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
++ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
++ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs);
++ dma->dma_paddr = 0;
++ dma->dma_map = NULL;
++ dma->dma_vaddr = NULL;
++ dma->nsegs = 0;
++ }
++}
++
++void *__DWC_ALLOC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
++}
++
++void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size)
++{
++ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
++}
++
++void __DWC_FREE(void *mem_ctx, void *addr)
++{
++ free(addr, M_DEVBUF);
++}
++
++
++#ifdef DWC_CRYPTOLIB
++/* dwc_crypto.h */
++
++void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length)
++{
++ get_random_bytes(buffer, length);
++}
++
++int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
++{
++ struct crypto_blkcipher *tfm;
++ struct blkcipher_desc desc;
++ struct scatterlist sgd;
++ struct scatterlist sgs;
++
++ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
++ if (tfm == NULL) {
++ printk("failed to load transform for aes CBC\n");
++ return -1;
++ }
++
++ crypto_blkcipher_setkey(tfm, key, keylen);
++ crypto_blkcipher_set_iv(tfm, iv, 16);
++
++ sg_init_one(&sgd, out, messagelen);
++ sg_init_one(&sgs, message, messagelen);
++
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) {
++ crypto_free_blkcipher(tfm);
++ DWC_ERROR("AES CBC encryption failed");
++ return -1;
++ }
++
++ crypto_free_blkcipher(tfm);
++ return 0;
++}
++
++int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, len);
++ crypto_hash_digest(&desc, &sg, len, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen,
++ uint8_t *key, uint32_t keylen, uint8_t *out)
++{
++ struct crypto_hash *tfm;
++ struct hash_desc desc;
++ struct scatterlist sg;
++
++ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC);
++ if (IS_ERR(tfm)) {
++ DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm));
++ return 0;
++ }
++ desc.tfm = tfm;
++ desc.flags = 0;
++
++ sg_init_one(&sg, message, messagelen);
++ crypto_hash_setkey(tfm, key, keylen);
++ crypto_hash_digest(&desc, &sg, messagelen, out);
++ crypto_free_hash(tfm);
++
++ return 1;
++}
++
++#endif /* DWC_CRYPTOLIB */
++
++
++/* Byte Ordering Conversions */
++
++uint32_t DWC_CPU_TO_LE32(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_CPU_TO_BE32(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_LE32_TO_CPU(uint32_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint32_t DWC_BE32_TO_CPU(uint32_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++
++ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24));
++#endif
++}
++
++uint16_t DWC_CPU_TO_LE16(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_CPU_TO_BE16(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_LE16_TO_CPU(uint16_t *p)
++{
++#ifdef __LITTLE_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++uint16_t DWC_BE16_TO_CPU(uint16_t *p)
++{
++#ifdef __BIG_ENDIAN
++ return *p;
++#else
++ uint8_t *u_p = (uint8_t *)p;
++ return (u_p[1] | (u_p[0] << 8));
++#endif
++}
++
++
++/* Registers */
++
++uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_4(io->iot, io->ioh, ior);
++}
++
++#if 0
++uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ return bus_space_read_8(io->iot, io->ioh, ior);
++}
++#endif
++
++void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior, value);
++}
++
++#if 0
++void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior, value);
++}
++#endif
++
++void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask,
++ uint32_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_4(io->iot, io->ioh, ior,
++ (bus_space_read_4(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++
++#if 0
++void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask,
++ uint64_t set_mask)
++{
++ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx;
++ bus_size_t ior = (bus_size_t)reg;
++
++ bus_space_write_8(io->iot, io->ioh, ior,
++ (bus_space_read_8(io->iot, io->ioh, ior) &
++ ~clear_mask) | set_mask);
++}
++#endif
++
++
++/* Locking */
++
++dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void)
++{
++ struct simplelock *sl = DWC_ALLOC(sizeof(*sl));
++
++ if (!sl) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ return NULL;
++ }
++
++ simple_lock_init(sl);
++ return (dwc_spinlock_t *)sl;
++}
++
++void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock)
++{
++ struct simplelock *sl = (struct simplelock *)lock;
++
++ DWC_FREE(sl);
++}
++
++void DWC_SPINLOCK(dwc_spinlock_t *lock)
++{
++ simple_lock((struct simplelock *)lock);
++}
++
++void DWC_SPINUNLOCK(dwc_spinlock_t *lock)
++{
++ simple_unlock((struct simplelock *)lock);
++}
++
++void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags)
++{
++ simple_lock((struct simplelock *)lock);
++ *flags = splbio();
++}
++
++void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags)
++{
++ splx(flags);
++ simple_unlock((struct simplelock *)lock);
++}
++
++dwc_mutex_t *DWC_MUTEX_ALLOC(void)
++{
++ dwc_mutex_t *mutex = DWC_ALLOC(sizeof(struct lock));
++
++ if (!mutex) {
++ DWC_ERROR("Cannot allocate memory for mutex");
++ return NULL;
++ }
++
++ lockinit((struct lock *)mutex, 0, "dw3mtx", 0, 0);
++ return mutex;
++}
++
++#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES))
++#else
++void DWC_MUTEX_FREE(dwc_mutex_t *mutex)
++{
++ DWC_FREE(mutex);
++}
++#endif
++
++void DWC_MUTEX_LOCK(dwc_mutex_t *mutex)
++{
++ lockmgr((struct lock *)mutex, LK_EXCLUSIVE, NULL);
++}
++
++int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex)
++{
++ int status;
++
++ status = lockmgr((struct lock *)mutex, LK_EXCLUSIVE | LK_NOWAIT, NULL);
++ return status == 0;
++}
++
++void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex)
++{
++ lockmgr((struct lock *)mutex, LK_RELEASE, NULL);
++}
++
++
++/* Timing */
++
++void DWC_UDELAY(uint32_t usecs)
++{
++ DELAY(usecs);
++}
++
++void DWC_MDELAY(uint32_t msecs)
++{
++ do {
++ DELAY(1000);
++ } while (--msecs);
++}
++
++void DWC_MSLEEP(uint32_t msecs)
++{
++ struct timeval tv;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++ tsleep(&tv, 0, "dw3slp", tvtohz(&tv));
++}
++
++uint32_t DWC_TIME(void)
++{
++ struct timeval tv;
++
++ microuptime(&tv); // or getmicrouptime? (less precise, but faster)
++ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
++}
++
++
++/* Timers */
++
++struct dwc_timer {
++ struct callout t;
++ char *name;
++ dwc_spinlock_t *lock;
++ dwc_timer_callback_t cb;
++ void *data;
++};
++
++dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data)
++{
++ dwc_timer_t *t = DWC_ALLOC(sizeof(*t));
++
++ if (!t) {
++ DWC_ERROR("Cannot allocate memory for timer");
++ return NULL;
++ }
++
++ callout_init(&t->t);
++
++ t->name = DWC_STRDUP(name);
++ if (!t->name) {
++ DWC_ERROR("Cannot allocate memory for timer->name");
++ goto no_name;
++ }
++
++ t->lock = DWC_SPINLOCK_ALLOC();
++ if (!t->lock) {
++ DWC_ERROR("Cannot allocate memory for timer->lock");
++ goto no_lock;
++ }
++
++ t->cb = cb;
++ t->data = data;
++
++ return t;
++
++ no_lock:
++ DWC_FREE(t->name);
++ no_name:
++ DWC_FREE(t);
++
++ return NULL;
++}
++
++void DWC_TIMER_FREE(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++ DWC_SPINLOCK_FREE(timer->lock);
++ DWC_FREE(timer->name);
++ DWC_FREE(timer);
++}
++
++void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time)
++{
++ struct timeval tv;
++
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data);
++}
++
++void DWC_TIMER_CANCEL(dwc_timer_t *timer)
++{
++ callout_stop(&timer->t);
++}
++
++
++/* Wait Queues */
++
++struct dwc_waitq {
++ struct simplelock lock;
++ int abort;
++};
++
++dwc_waitq_t *DWC_WAITQ_ALLOC(void)
++{
++ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ return NULL;
++ }
++
++ simple_lock_init(&wq->lock);
++ wq->abort = 0;
++
++ return wq;
++}
++
++void DWC_WAITQ_FREE(dwc_waitq_t *wq)
++{
++ DWC_FREE(wq);
++}
++
++int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data)
++{
++ int ipl;
++ int result = 0;
++
++ simple_lock(&wq->lock);
++ ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++ splx(ipl);
++ result = ltsleep(wq, PCATCH, "dw3wat", 0, &wq->lock); // infinite timeout
++ ipl = splbio();
++ }
++
++ if (result == 0) { // awoken
++ if (wq->abort) {
++ wq->abort = 0;
++ result = -DWC_E_ABORT;
++ } else {
++ result = 0;
++ }
++
++ splx(ipl);
++ simple_unlock(&wq->lock);
++ } else {
++ wq->abort = 0;
++ splx(ipl);
++ simple_unlock(&wq->lock);
++
++ if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++ } else { // signaled - must be EINTR
++ result = -DWC_E_ABORT;
++ }
++ }
++
++ return result;
++}
++
++int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond,
++ void *data, int32_t msecs)
++{
++ struct timeval tv, tv1, tv2;
++ int ipl;
++ int result = 0;
++
++ tv.tv_sec = msecs / 1000;
++ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
++
++ simple_lock(&wq->lock);
++ ipl = splbio();
++
++ /* Skip the sleep if already aborted or triggered */
++ if (!wq->abort && !cond(data)) {
++ splx(ipl);
++ getmicrouptime(&tv1);
++ result = ltsleep(wq, PCATCH, "dw3wto", tvtohz(&tv), &wq->lock);
++ getmicrouptime(&tv2);
++ ipl = splbio();
++ }
++
++ if (result == 0) { // awoken
++ if (wq->abort) {
++ wq->abort = 0;
++ splx(ipl);
++ simple_unlock(&wq->lock);
++ result = -DWC_E_ABORT;
++ } else {
++ splx(ipl);
++ simple_unlock(&wq->lock);
++
++ tv2.tv_usec -= tv1.tv_usec;
++ if (tv2.tv_usec < 0) {
++ tv2.tv_usec += 1000000;
++ tv2.tv_sec--;
++ }
++
++ tv2.tv_sec -= tv1.tv_sec;
++ result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000;
++ result = msecs - result;
++ if (result <= 0)
++ result = 1;
++ }
++ } else {
++ wq->abort = 0;
++ splx(ipl);
++ simple_unlock(&wq->lock);
++
++ if (result == ERESTART) { // signaled - restart
++ result = -DWC_E_RESTART;
++
++ } else if (result == EINTR) { // signaled - interrupt
++ result = -DWC_E_ABORT;
++
++ } else { // timed out
++ result = -DWC_E_TIMEOUT;
++ }
++ }
++
++ return result;
++}
++
++void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq)
++{
++ wakeup(wq);
++}
++
++void DWC_WAITQ_ABORT(dwc_waitq_t *wq)
++{
++ int ipl;
++
++ simple_lock(&wq->lock);
++ ipl = splbio();
++ wq->abort = 1;
++ wakeup(wq);
++ splx(ipl);
++ simple_unlock(&wq->lock);
++}
++
++
++/* Threading */
++
++struct dwc_thread {
++ struct proc *proc;
++ int abort;
++};
++
++dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data)
++{
++ int retval;
++ dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread));
++
++ if (!thread) {
++ return NULL;
++ }
++
++ thread->abort = 0;
++ retval = kthread_create1((void (*)(void *))func, data, &thread->proc,
++ "%s", name);
++ if (retval) {
++ DWC_FREE(thread);
++ return NULL;
++ }
++
++ return thread;
++}
++
++int DWC_THREAD_STOP(dwc_thread_t *thread)
++{
++ int retval;
++
++ thread->abort = 1;
++ retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz);
++
++ if (retval == 0) {
++ /* DWC_THREAD_EXIT() will free the thread struct */
++ return 0;
++ }
++
++ /* NOTE: We leak the thread struct if thread doesn't die */
++
++ if (retval == EWOULDBLOCK) {
++ return -DWC_E_TIMEOUT;
++ }
++
++ return -DWC_E_UNKNOWN;
++}
++
++dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread)
++{
++ return thread->abort;
++}
++
++void DWC_THREAD_EXIT(dwc_thread_t *thread)
++{
++ wakeup(&thread->abort);
++ DWC_FREE(thread);
++ kthread_exit(0);
++}
++
++/* tasklets
++ - Runs in interrupt context (cannot sleep)
++ - Each tasklet runs on a single CPU
++ - Different tasklets can be running simultaneously on different CPUs
++ [ On NetBSD there is no corresponding mechanism, drivers don't have bottom-
++ halves. So we just call the callback directly from DWC_TASK_SCHEDULE() ]
++ */
++struct dwc_tasklet {
++ dwc_tasklet_callback_t cb;
++ void *data;
++};
++
++static void tasklet_callback(void *data)
++{
++ dwc_tasklet_t *task = (dwc_tasklet_t *)data;
++
++ task->cb(task->data);
++}
++
++dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data)
++{
++ dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task));
++
++ if (task) {
++ task->cb = cb;
++ task->data = data;
++ } else {
++ DWC_ERROR("Cannot allocate memory for tasklet");
++ }
++
++ return task;
++}
++
++void DWC_TASK_FREE(dwc_tasklet_t *task)
++{
++ DWC_FREE(task);
++}
++
++void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
++{
++ tasklet_callback(task);
++}
++
++
++/* workqueues
++ - Runs in process context (can sleep)
++ */
++typedef struct work_container {
++ dwc_work_callback_t cb;
++ void *data;
++ dwc_workq_t *wq;
++ char *name;
++ int hz;
++ struct work task;
++} work_container_t;
++
++struct dwc_workq {
++ struct workqueue *taskq;
++ dwc_spinlock_t *lock;
++ dwc_waitq_t *waitq;
++ int pending;
++ struct work_container *container;
++};
++
++static void do_work(struct work *task, void *data)
++{
++ dwc_workq_t *wq = (dwc_workq_t *)data;
++ work_container_t *container = wq->container;
++ dwc_irqflags_t flags;
++
++ if (container->hz) {
++ tsleep(container, 0, "dw3wrk", container->hz);
++ }
++
++ container->cb(container->data);
++ DWC_DEBUG("Work done: %s, container=%p", container->name, container);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ if (container->name)
++ DWC_FREE(container->name);
++ DWC_FREE(container);
++ wq->pending--;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++}
++
++static int work_done(void *data)
++{
++ dwc_workq_t *workq = (dwc_workq_t *)data;
++
++ return workq->pending == 0;
++}
++
++int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout)
++{
++ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout);
++}
++
++dwc_workq_t *DWC_WORKQ_ALLOC(char *name)
++{
++ int result;
++ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq));
++
++ if (!wq) {
++ DWC_ERROR("Cannot allocate memory for workqueue");
++ return NULL;
++ }
++
++ result = workqueue_create(&wq->taskq, name, do_work, wq, 0 /*PWAIT*/,
++ IPL_BIO, 0);
++ if (result) {
++ DWC_ERROR("Cannot create workqueue");
++ goto no_taskq;
++ }
++
++ wq->pending = 0;
++
++ wq->lock = DWC_SPINLOCK_ALLOC();
++ if (!wq->lock) {
++ DWC_ERROR("Cannot allocate memory for spinlock");
++ goto no_lock;
++ }
++
++ wq->waitq = DWC_WAITQ_ALLOC();
++ if (!wq->waitq) {
++ DWC_ERROR("Cannot allocate memory for waitqueue");
++ goto no_waitq;
++ }
++
++ return wq;
++
++ no_waitq:
++ DWC_SPINLOCK_FREE(wq->lock);
++ no_lock:
++ workqueue_destroy(wq->taskq);
++ no_taskq:
++ DWC_FREE(wq);
++
++ return NULL;
++}
++
++void DWC_WORKQ_FREE(dwc_workq_t *wq)
++{
++#ifdef DEBUG
++ dwc_irqflags_t flags;
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++
++ if (wq->pending != 0) {
++ struct work_container *container = wq->container;
++
++ DWC_ERROR("Destroying work queue with pending work");
++
++ if (container && container->name) {
++ DWC_ERROR("Work %s still pending", container->name);
++ }
++ }
++
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++#endif
++ DWC_WAITQ_FREE(wq->waitq);
++ DWC_SPINLOCK_FREE(wq->lock);
++ workqueue_destroy(wq->taskq);
++ DWC_FREE(wq);
++}
++
++void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data,
++ char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ container->hz = 0;
++ wq->container = container;
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++ workqueue_enqueue(wq->taskq, &container->task);
++}
++
++void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb,
++ void *data, uint32_t time, char *format, ...)
++{
++ dwc_irqflags_t flags;
++ work_container_t *container;
++ static char name[128];
++ struct timeval tv;
++ va_list args;
++
++ va_start(args, format);
++ DWC_VSNPRINTF(name, 128, format, args);
++ va_end(args);
++
++ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags);
++ wq->pending++;
++ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags);
++ DWC_WAITQ_TRIGGER(wq->waitq);
++
++ container = DWC_ALLOC_ATOMIC(sizeof(*container));
++ if (!container) {
++ DWC_ERROR("Cannot allocate memory for container");
++ return;
++ }
++
++ container->name = DWC_STRDUP(name);
++ if (!container->name) {
++ DWC_ERROR("Cannot allocate memory for container->name");
++ DWC_FREE(container);
++ return;
++ }
++
++ container->cb = cb;
++ container->data = data;
++ container->wq = wq;
++ tv.tv_sec = time / 1000;
++ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000;
++ container->hz = tvtohz(&tv);
++ wq->container = container;
++
++ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container);
++ workqueue_enqueue(wq->taskq, &container->task);
++}
++
++int DWC_WORKQ_PENDING(dwc_workq_t *wq)
++{
++ return wq->pending;
++}
+diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.c b/drivers/usb/host/dwc_common_port/dwc_crypto.c
+new file mode 100644
+index 000000000000..3b0353296148
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c
+@@ -0,0 +1,308 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $
++ * $Revision: #5 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++
++/** @file
++ * This file contains the WUSB cryptographic routines.
++ */
++
++#ifdef DWC_CRYPTOLIB
++
++#include "dwc_crypto.h"
++#include "usb.h"
++
++#ifdef DEBUG
++static inline void dump_bytes(char *name, uint8_t *bytes, int len)
++{
++ int i;
++ DWC_PRINTF("%s: ", name);
++ for (i=0; i<len; i++) {
++ DWC_PRINTF("%02x ", bytes[i]);
++ }
++ DWC_PRINTF("\n");
++}
++#else
++#define dump_bytes(x...)
++#endif
++
++/* Display a block */
++void show_block(const u8 *blk, const char *prefix, const char *suffix, int a)
++{
++#ifdef DWC_DEBUG_CRYPTO
++ int i, blksize = 16;
++
++ DWC_DEBUG("%s", prefix);
++
++ if (suffix == NULL) {
++ suffix = "\n";
++ blksize = a;
++ }
++
++ for (i = 0; i < blksize; i++)
++ DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " ");
++ DWC_PRINT(suffix);
++#endif
++}
++
++/**
++ * Encrypts an array of bytes using the AES encryption engine.
++ * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted
++ * in-place.
++ *
++ * @return 0 on success, negative error code on error.
++ */
++int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst)
++{
++ u8 block_t[16];
++ DWC_MEMSET(block_t, 0, 16);
++
++ return DWC_AES_CBC(src, 16, key, 16, block_t, dst);
++}
++
++/**
++ * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
++ * This function takes a data string and returns the encrypted CBC
++ * Counter-mode MIC.
++ *
++ * @param key The 128-bit symmetric key.
++ * @param nonce The CCM nonce.
++ * @param label The unique 14-byte ASCII text label.
++ * @param bytes The byte array to be encrypted.
++ * @param len Length of the byte array.
++ * @param result Byte array to receive the 8-byte encrypted MIC.
++ */
++void dwc_wusb_cmf(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ u8 block_m[16];
++ u8 block_x[16];
++ u8 block_t[8];
++ int idx, blkNum;
++ u16 la = (u16)(len + 14);
++
++ /* Set the AES-128 key */
++ //dwc_aes_setkey(tfm, key, 16);
++
++ /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */
++ block_m[0] = 0x59;
++ for (idx = 0; idx < 13; idx++)
++ block_m[idx + 1] = nonce[idx];
++ block_m[14] = 0;
++ block_m[15] = 0;
++
++ /* Produce the CBC IV */
++ dwc_wusb_aes_encrypt(block_m, key, block_x);
++ show_block(block_m, "CBC IV in: ", "\n", 0);
++ show_block(block_x, "CBC IV out:", "\n", 0);
++
++ /* Fill block B1 from l(a) = Blen + 14, and A */
++ block_x[0] ^= (u8)(la >> 8);
++ block_x[1] ^= (u8)la;
++ for (idx = 0; idx < 14; idx++)
++ block_x[idx + 2] ^= label[idx];
++ show_block(block_x, "After xor: ", "b1\n", 16);
++
++ dwc_wusb_aes_encrypt(block_x, key, block_x);
++ show_block(block_x, "After AES: ", "b1\n", 16);
++
++ idx = 0;
++ blkNum = 0;
++
++ /* Fill remaining blocks with B */
++ while (len-- > 0) {
++ block_x[idx] ^= *bytes++;
++ if (++idx >= 16) {
++ idx = 0;
++ show_block(block_x, "After xor: ", "\n", blkNum);
++ dwc_wusb_aes_encrypt(block_x, key, block_x);
++ show_block(block_x, "After AES: ", "\n", blkNum);
++ blkNum++;
++ }
++ }
++
++ /* Handle partial last block */
++ if (idx > 0) {
++ show_block(block_x, "After xor: ", "\n", blkNum);
++ dwc_wusb_aes_encrypt(block_x, key, block_x);
++ show_block(block_x, "After AES: ", "\n", blkNum);
++ }
++
++ /* Save the MIC tag */
++ DWC_MEMCPY(block_t, block_x, 8);
++ show_block(block_t, "MIC tag : ", NULL, 8);
++
++ /* Fill block A0 from flags = 0x01, N, and counter = 0 */
++ block_m[0] = 0x01;
++ block_m[14] = 0;
++ block_m[15] = 0;
++
++ /* Encrypt the counter */
++ dwc_wusb_aes_encrypt(block_m, key, block_x);
++ show_block(block_x, "CTR[MIC] : ", NULL, 8);
++
++ /* XOR with MIC tag */
++ for (idx = 0; idx < 8; idx++) {
++ block_t[idx] ^= block_x[idx];
++ }
++
++ /* Return result to caller */
++ DWC_MEMCPY(result, block_t, 8);
++ show_block(result, "CCM-MIC : ", NULL, 8);
++
++}
++
++/**
++ * The PRF function described in section 6.5 of the WUSB spec. This function
++ * concatenates MIC values returned from dwc_cmf() to create a value of
++ * the requested length.
++ *
++ * @param prf_len Length of the PRF function in bits (64, 128, or 256).
++ * @param key, nonce, label, bytes, len Same as for dwc_cmf().
++ * @param result Byte array to receive the result.
++ */
++void dwc_wusb_prf(int prf_len, u8 *key,
++ u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
++{
++ int i;
++
++ nonce[0] = 0;
++ for (i = 0; i < prf_len >> 6; i++, nonce[0]++) {
++ dwc_wusb_cmf(key, nonce, label, bytes, len, result);
++ result += 8;
++ }
++}
++
++/**
++ * Fills in CCM Nonce per the WUSB spec.
++ *
++ * @param[in] haddr Host address.
++ * @param[in] daddr Device address.
++ * @param[in] tkid Session Key(PTK) identifier.
++ * @param[out] nonce Pointer to where the CCM Nonce output is to be written.
++ */
++void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
++ uint8_t *nonce)
++{
++
++ DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr);
++
++ DWC_MEMSET(&nonce[0], 0, 16);
++
++ DWC_MEMCPY(&nonce[6], tkid, 3);
++ nonce[9] = daddr & 0xFF;
++ nonce[10] = (daddr >> 8) & 0xFF;
++ nonce[11] = haddr & 0xFF;
++ nonce[12] = (haddr >> 8) & 0xFF;
++
++ dump_bytes("CCM nonce", nonce, 16);
++}
++
++/**
++ * Generates a 16-byte cryptographic-grade random number for the Host/Device
++ * Nonce.
++ */
++void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce)
++{
++ uint8_t inonce[16];
++ uint32_t temp[4];
++
++ /* Fill in the Nonce */
++ DWC_MEMSET(&inonce[0], 0, sizeof(inonce));
++ inonce[9] = addr & 0xFF;
++ inonce[10] = (addr >> 8) & 0xFF;
++ inonce[11] = inonce[9];
++ inonce[12] = inonce[10];
++
++ /* Collect "randomness samples" */
++ DWC_RANDOM_BYTES((uint8_t *)temp, 16);
++
++ dwc_wusb_prf_128((uint8_t *)temp, nonce,
++ "Random Numbers", (uint8_t *)temp, sizeof(temp),
++ nonce);
++}
++
++/**
++ * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the
++ * WUSB spec.
++ *
++ * @param[in] ccm_nonce Pointer to CCM Nonce.
++ * @param[in] mk Master Key to derive the session from
++ * @param[in] hnonce Pointer to Host Nonce.
++ * @param[in] dnonce Pointer to Device Nonce.
++ * @param[out] kck Pointer to where the KCK output is to be written.
++ * @param[out] ptk Pointer to where the PTK output is to be written.
++ */
++void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce,
++ uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
++{
++ uint8_t idata[32];
++ uint8_t odata[32];
++
++ dump_bytes("ck", mk, 16);
++ dump_bytes("hnonce", hnonce, 16);
++ dump_bytes("dnonce", dnonce, 16);
++
++ /* The data is the HNonce and DNonce concatenated */
++ DWC_MEMCPY(&idata[0], hnonce, 16);
++ DWC_MEMCPY(&idata[16], dnonce, 16);
++
++ dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata);
++
++ /* Low 16 bytes of the result is the KCK, high 16 is the PTK */
++ DWC_MEMCPY(kck, &odata[0], 16);
++ DWC_MEMCPY(ptk, &odata[16], 16);
++
++ dump_bytes("kck", kck, 16);
++ dump_bytes("ptk", ptk, 16);
++}
++
++/**
++ * Generates the Message Integrity Code over the Handshake data per the
++ * WUSB spec.
++ *
++ * @param ccm_nonce Pointer to CCM Nonce.
++ * @param kck Pointer to Key Confirmation Key.
++ * @param data Pointer to Handshake data to be checked.
++ * @param mic Pointer to where the MIC output is to be written.
++ */
++void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck,
++ uint8_t *data, uint8_t *mic)
++{
++
++ dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC",
++ data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic);
++}
++
++#endif /* DWC_CRYPTOLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.h b/drivers/usb/host/dwc_common_port/dwc_crypto.h
+new file mode 100644
+index 000000000000..26fcddcfe9ba
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h
+@@ -0,0 +1,111 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.h $
++ * $Revision: #3 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++
++#ifndef _DWC_CRYPTO_H_
++#define _DWC_CRYPTO_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/** @file
++ *
++ * This file contains declarations for the WUSB Cryptographic routines as
++ * defined in the WUSB spec. They are only to be used internally by the DWC UWB
++ * modules.
++ */
++
++#include "dwc_os.h"
++
++int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst);
++
++void dwc_wusb_cmf(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result);
++void dwc_wusb_prf(int prf_len, u8 *key,
++ u8 *nonce, char *label, u8 *bytes, int len, u8 *result);
++
++/**
++ * The PRF-64 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ dwc_wusb_prf(64, key, nonce, label, bytes, len, result);
++}
++
++/**
++ * The PRF-128 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ dwc_wusb_prf(128, key, nonce, label, bytes, len, result);
++}
++
++/**
++ * The PRF-256 function described in section 6.5 of the WUSB spec.
++ *
++ * @param key, nonce, label, bytes, len, result Same as for dwc_prf().
++ */
++static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce,
++ char *label, u8 *bytes, int len, u8 *result)
++{
++ dwc_wusb_prf(256, key, nonce, label, bytes, len, result);
++}
++
++
++void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid,
++ uint8_t *nonce);
++void dwc_wusb_gen_nonce(uint16_t addr,
++ uint8_t *nonce);
++
++void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk,
++ uint8_t *hnonce, uint8_t *dnonce,
++ uint8_t *kck, uint8_t *ptk);
++
++
++void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t
++ *kck, uint8_t *data, uint8_t *mic);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _DWC_CRYPTO_H_ */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.c b/drivers/usb/host/dwc_common_port/dwc_dh.c
+new file mode 100644
+index 000000000000..2b429a32aaf0
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_dh.c
+@@ -0,0 +1,291 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
++ * $Revision: #3 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifdef DWC_CRYPTOLIB
++
++#ifndef CONFIG_MACH_IPMATE
++
++#include "dwc_dh.h"
++#include "dwc_modpow.h"
++
++#ifdef DEBUG
++/* This function prints out a buffer in the format described in the Association
++ * Model specification. */
++static void dh_dump(char *str, void *_num, int len)
++{
++ uint8_t *num = _num;
++ int i;
++ DWC_PRINTF("%s\n", str);
++ for (i = 0; i < len; i ++) {
++ DWC_PRINTF("%02x", num[i]);
++ if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
++ if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
++ }
++
++ DWC_PRINTF("\n");
++}
++#else
++#define dh_dump(_x...) do {; } while(0)
++#endif
++
++/* Constant g value */
++static __u32 dh_g[] = {
++ 0x02000000,
++};
++
++/* Constant p value */
++static __u32 dh_p[] = {
++ 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
++ 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
++ 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
++ 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
++ 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
++ 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
++ 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
++ 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
++ 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
++ 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
++ 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
++ 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
++};
++
++static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
++{
++ uint8_t *in = _in;
++ uint8_t *out = _out;
++ int i;
++ for (i=0; i<len; i++) {
++ out[i] = in[len-1-i];
++ }
++}
++
++/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
++ * big endian numbers of size len, in bytes. Each len value must be a multiple
++ * of 4. */
++int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
++ void *exp, uint32_t exp_len,
++ void *mod, uint32_t mod_len,
++ void *out)
++{
++ /* modpow() takes little endian numbers. AM uses big-endian. This
++ * function swaps bytes of numbers before passing onto modpow. */
++
++ int retval = 0;
++ uint32_t *result;
++
++ uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
++ uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
++ uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
++
++ dh_swap_bytes(num, &bignum_num[1], num_len);
++ bignum_num[0] = num_len / 4;
++
++ dh_swap_bytes(exp, &bignum_exp[1], exp_len);
++ bignum_exp[0] = exp_len / 4;
++
++ dh_swap_bytes(mod, &bignum_mod[1], mod_len);
++ bignum_mod[0] = mod_len / 4;
++
++ result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
++ if (!result) {
++ retval = -1;
++ goto dh_modpow_nomem;
++ }
++
++ dh_swap_bytes(&result[1], out, result[0] * 4);
++ dwc_free(mem_ctx, result);
++
++ dh_modpow_nomem:
++ dwc_free(mem_ctx, bignum_num);
++ dwc_free(mem_ctx, bignum_exp);
++ dwc_free(mem_ctx, bignum_mod);
++ return retval;
++}
++
++
++int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
++{
++ int retval;
++ uint8_t m3[385];
++
++#ifndef DH_TEST_VECTORS
++ DWC_RANDOM_BYTES(exp, 32);
++#endif
++
++ /* Compute the pkd */
++ if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
++ exp, 32,
++ dh_p, 384, pk))) {
++ return retval;
++ }
++
++ m3[384] = nd;
++ DWC_MEMCPY(&m3[0], pk, 384);
++ DWC_SHA256(m3, 385, hash);
++
++ dh_dump("PK", pk, 384);
++ dh_dump("SHA-256(M3)", hash, 32);
++ return 0;
++}
++
++int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
++ uint8_t *exp, int is_host,
++ char *dd, uint8_t *ck, uint8_t *kdk)
++{
++ int retval;
++ uint8_t mv[784];
++ uint8_t sha_result[32];
++ uint8_t dhkey[384];
++ uint8_t shared_secret[384];
++ char *message;
++ uint32_t vd;
++
++ uint8_t *pk;
++
++ if (is_host) {
++ pk = pkd;
++ }
++ else {
++ pk = pkh;
++ }
++
++ if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
++ exp, 32,
++ dh_p, 384, shared_secret))) {
++ return retval;
++ }
++ dh_dump("Shared Secret", shared_secret, 384);
++
++ DWC_SHA256(shared_secret, 384, dhkey);
++ dh_dump("DHKEY", dhkey, 384);
++
++ DWC_MEMCPY(&mv[0], pkd, 384);
++ DWC_MEMCPY(&mv[384], pkh, 384);
++ DWC_MEMCPY(&mv[768], "displayed digest", 16);
++ dh_dump("MV", mv, 784);
++
++ DWC_SHA256(mv, 784, sha_result);
++ dh_dump("SHA-256(MV)", sha_result, 32);
++ dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
++
++ dh_swap_bytes(sha_result, &vd, 4);
++#ifdef DEBUG
++ DWC_PRINTF("Vd (decimal) = %d\n", vd);
++#endif
++
++ switch (nd) {
++ case 2:
++ vd = vd % 100;
++ DWC_SPRINTF(dd, "%02d", vd);
++ break;
++ case 3:
++ vd = vd % 1000;
++ DWC_SPRINTF(dd, "%03d", vd);
++ break;
++ case 4:
++ vd = vd % 10000;
++ DWC_SPRINTF(dd, "%04d", vd);
++ break;
++ }
++#ifdef DEBUG
++ DWC_PRINTF("Display Digits: %s\n", dd);
++#endif
++
++ message = "connection key";
++ DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
++ dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
++ DWC_MEMCPY(ck, sha_result, 16);
++
++ message = "key derivation key";
++ DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
++ dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
++ DWC_MEMCPY(kdk, sha_result, 32);
++
++ return 0;
++}
++
++
++#ifdef DH_TEST_VECTORS
++
++static __u8 dh_a[] = {
++ 0x44, 0x00, 0x51, 0xd6,
++ 0xf0, 0xb5, 0x5e, 0xa9,
++ 0x67, 0xab, 0x31, 0xc6,
++ 0x8a, 0x8b, 0x5e, 0x37,
++ 0xd9, 0x10, 0xda, 0xe0,
++ 0xe2, 0xd4, 0x59, 0xa4,
++ 0x86, 0x45, 0x9c, 0xaa,
++ 0xdf, 0x36, 0x75, 0x16,
++};
++
++static __u8 dh_b[] = {
++ 0x5d, 0xae, 0xc7, 0x86,
++ 0x79, 0x80, 0xa3, 0x24,
++ 0x8c, 0xe3, 0x57, 0x8f,
++ 0xc7, 0x5f, 0x1b, 0x0f,
++ 0x2d, 0xf8, 0x9d, 0x30,
++ 0x6f, 0xa4, 0x52, 0xcd,
++ 0xe0, 0x7a, 0x04, 0x8a,
++ 0xde, 0xd9, 0x26, 0x56,
++};
++
++void dwc_run_dh_test_vectors(void *mem_ctx)
++{
++ uint8_t pkd[384];
++ uint8_t pkh[384];
++ uint8_t hashd[32];
++ uint8_t hashh[32];
++ uint8_t ck[16];
++ uint8_t kdk[32];
++ char dd[5];
++
++ DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
++
++ /* compute the PKd and SHA-256(PKd || Nd) */
++ DWC_PRINTF("Computing PKd\n");
++ dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
++
++ /* compute the PKd and SHA-256(PKh || Nd) */
++ DWC_PRINTF("Computing PKh\n");
++ dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
++
++ /* compute the dhkey */
++ dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
++}
++#endif /* DH_TEST_VECTORS */
++
++#endif /* !CONFIG_MACH_IPMATE */
++
++#endif /* DWC_CRYPTOLIB */
+diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.h b/drivers/usb/host/dwc_common_port/dwc_dh.h
+new file mode 100644
+index 000000000000..25c1cc0d588a
+--- /dev/null
++++ b/drivers/usb/host/dwc_common_port/dwc_dh.h
+@@ -0,0 +1,106 @@
++/* =========================================================================
++ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.h $
++ * $Revision: #4 $
++ * $Date: 2010/09/28 $
++ * $Change: 1596182 $
++ *
++ * Synopsys Portability Library Software and documentation
++ * (hereinafter, "Software") is an Unsupported proprietary work of
++ * Synopsys, Inc. unless otherwise expressly agreed to in writing
++ * between Synopsys and you.
++ *
++ * The Software IS NOT an item of Licensed Software or Licensed Product
++ * under any End User Software License Agreement or Agreement for
++ * Licensed Product with Synopsys or any supplement thereto. You are
++ * permitted to use and redistribute this Software in source and binary
++ * forms, with or without modification, provided that redistributions
++ * of source code must retain this notice. You may not view, use,
++ * disclose, copy or distribute this file or any information contained
++ * herein except pursuant to this license grant from Synopsys. If you
++ * do not agree with this notice, including the disclaimer below, then
++ * you are not authorized to use the Software.
++ *
++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
++ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
++ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ * ========================================================================= */
++#ifndef _DWC_DH_H_
++#define _DWC_DH_H_
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include "dwc_os.h"
++
++/** @file
++ *
++ * This file defines the common functions on device and host for performing
++ * numeric association as defined in the WUSB spec. They are only to be
++ * used internally by the DWC UWB modules. */
++
++extern int dwc_dh_sha256(uint8_t *message, uint32_t len, uint8_t *out);
++ex