kernel: copy kernel 4.19 code to 5.4
authorHauke Mehrtens <hauke@hauke-m.de>
Sun, 23 Feb 2020 12:20:11 +0000 (13:20 +0100)
committerKoen Vandeputte <koen.vandeputte@ncentric.com>
Fri, 28 Feb 2020 16:50:45 +0000 (17:50 +0100)
No changes were done to the patches while coping them. Currently they do
not apply on top of kernel 5.4.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
228 files changed:
target/linux/generic/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/011-kbuild-export-SUBARCH.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/020-backport_netfilter_rtcache.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/047-v4.21-mtd-keep-original-flags-for-every-struct-mtd_info.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/048-v4.21-mtd-improve-calculating-partition-boundaries-when-ch.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/080-v5.1-0001-bcma-keep-a-direct-pointer-to-the-struct-device.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/080-v5.1-0002-bcma-use-dev_-printing-functions.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/095-Allow-class-e-address-assignment-via-ifconfig-ioctl.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/101-arm-cns3xxx-use-actual-size-reads-for-PCIe.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/200-v5.2-usb-dwc2-Set-lpm-mode-parameters-depend-on-HW-configuration.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/210-arm64-sve-Disentangle-uapi-asm-ptrace.h-from-uapi-as.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/380-v5.3-net-sched-Introduce-act_ctinfo-action.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/450-v5.0-mtd-spinand-winbond-Add-support-for-W25N01GV.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/451-v5.0-mtd-spinand-Add-initial-support-for-Toshiba-TC58CVG2.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/452-v5.0-mtd-spinand-add-support-for-GigaDevice-GD5FxGQ4xA.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/455-v5.1-mtd-spinand-Add-support-for-all-Toshiba-Memory-produ.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/456-v5.1-mtd-spinand-Add-support-for-GigaDevice-GD5F1GQ4UExxG.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/460-v5.0-mtd-spi-nor-Add-support-for-mx25u12835f.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/460-v5.3-mtd-spinand-Define-macros-for-page-read-ops-with-thr.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/461-v5.3-mtd-spinand-Add-support-for-two-byte-device-IDs.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/462-v5.3-mtd-spinand-Add-support-for-GigaDevice-GD5F1GQ4UFxxG.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/463-v5.3-mtd-spinand-Add-initial-support-for-Paragon-PN26G0xA.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/700-v5.1-net-phylink-only-call-mac_config-during-resolve-when.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/701-v5.2-net-phylink-ensure-inband-AN-works-correctly.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/702-v4.20-net-ethernet-Add-helper-for-MACs-which-support-asym-.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/703-v4.20-net-ethernet-Add-helper-for-set_pauseparam-for-Asym-.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/704-v4.20-net-phy-Stop-with-excessive-soft-reset.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/705-v5.1-net-phy-provide-full-set-of-accessor-functions-to-MM.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/706-v5.1-net-phy-add-register-modifying-helpers-returning-1-o.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/707-v5.1-net-phy-add-genphy_c45_check_and_restart_aneg.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/708-v5.3-net-phylink-remove-netdev-from-phylink-mii-ioctl-emu.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/709-v5.3-net-phylink-support-for-link-gpio-interrupt.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/710-v5.3-net-phy-allow-Clause-45-access-via-mii-ioctl.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/711-v5.3-net-sfp-add-mandatory-attach-detach-methods-for-sfp-.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/712-v5.3-net-sfp-remove-sfp-bus-use-of-netdevs.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/713-v5.2-net-phylink-avoid-reducing-support-mask.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/715-v5.3-net-phylink-don-t-start-and-stop-SGMII-PHYs-in-SFP-m.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/716-v5.4-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/734-v5.5-net-sfp-move-module-insert-reporting-out-of-probe.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/735-v5.5-net-sfp-allow-sfp-to-probe-slow-to-initialise-GPON-m.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/736-v5.5-net-sfp-allow-modules-with-slow-diagnostics-to-probe.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/737-v5.5-net-phy-add-core-phylib-sfp-support.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/738-v5.5-net-phy-marvell10g-add-SFP-support.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/739-v5.5-net-phylink-update-to-use-phy_support_asym_pause.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/740-v5.5-net-phy-avoid-matching-all-ones-clause-45-PHY-IDs.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/741-v5.5-net-phylink-fix-link-mode-modification-in-PHY-mode.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/742-v5.5-net-sfp-add-support-for-module-quirks.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/743-v5.5-net-sfp-add-some-quirks-for-GPON-modules.patch [new file with mode: 0644]
target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch [new file with mode: 0644]
target/linux/generic/config-5.4 [new file with mode: 0644]
target/linux/generic/hack-5.4/204-module_strip.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/207-disable-modorder.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/210-darwin_scripts_include.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/212-byteshift_portability.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/214-spidev_h_portability.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/220-gc_sections.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/221-module_exports.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/230-openwrt_lzma_options.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/250-netfilter_depends.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/251-sound_kconfig.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/259-regmap_dynamic.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/260-crypto_test_dependencies.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/280-rfkill-stubs.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/290-nvmem-make-CONFIG_NVMEM-tristate-again.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/301-mips_image_cmdline_hack.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/321-powerpc_crtsavres_prereq.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/531-debloat_lzma.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/550-loop-Report-EOPNOTSUPP-properly.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/551-loop-Better-discard-support-for-block-devices.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/640-bridge-only-accept-EAP-locally.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/645-netfilter-connmark-introduce-set-dscpmark.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/647-netfilter-flow-acct.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/650-netfilter-add-xt_OFFLOAD-target.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/651-wireless_mesh_header.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/660-fq_codel_defaults.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/661-use_fq_codel_by_default.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/662-remove_pfifo_fast.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/700-swconfig_switch_drivers.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/702-phy_add_aneg_done_function.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/721-phy_packets.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/773-bgmac-add-srab-switch.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/901-debloat_sock_diag.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/902-debloat_proc.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/904-debloat_dma_buf.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/910-kobject_uevent.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/911-kobject_add_broadcast_uevent.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/921-always-create-console-node-in-initramfs.patch [new file with mode: 0644]
target/linux/generic/hack-5.4/930-crashlog.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/0931-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/103-MIPS-perf-ath79-Fix-perfcount-IRQ-assignment.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/110-ehci_hcd_ignore_oc.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/130-add-linux-spidev-compatible-si3210.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/131-spi-use-gpio_set_value_cansleep-for-setting-chipsele.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/132-spi-spi-gpio-fix-crash-when-num-chipselects-is-0.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/141-jffs2-add-RENAME_EXCHANGE-support.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/150-bridge_allow_receiption_on_disabled_port.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/180-net-phy-at803x-add-support-for-AT8032.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/201-extra_optimization.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/203-kallsyms_uncompressed.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/205-backtrace_module_info.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/220-optimize_inlining.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/240-remove-unsane-filenames-from-deps_initramfs-list.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/261-enable_wilink_platform_without_drivers.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/300-mips_expose_boot_raw.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/302-mips_no_branch_likely.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/304-mips_disable_fpu.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/305-mips_module_reloc.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/306-mips_mem_functions_performance.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/307-mips_highmem_offset.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/308-mips32r2_tune.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/309-MIPS-Add-CPU-option-reporting-to-proc-cpuinfo.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/310-arm_module_unresolved_weak_sym.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/332-arc-add-OWRTDTB-section.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/333-arc-enable-unaligned-access-in-kernel-mode.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/341-MIPS-mm-remove-no-op-dma_map_ops-where-possible.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/400-mtd-add-rootfs-split-support.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/401-mtd-add-support-for-different-partition-parser-types.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/402-mtd-use-typed-mtd-parsers-for-rootfs-and-firmware-split.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/403-mtd-hook-mtdsplit-to-Kbuild.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/404-mtd-add-more-helper-functions.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/411-mtd-partial_eraseblock_write.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/412-mtd-partial_eraseblock_unlock.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/419-mtd-redboot-add-of_match_table-with-DT-binding.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/420-mtd-redboot_space.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/430-mtd-add-myloader-partition-parser.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/440-block2mtd_init.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/441-block2mtd_probe.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/450-mtd-spi-nor-allow-NOR-driver-to-write-fewer-bytes-th.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/465-m25p80-mx-disable-software-protection.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/466-Revert-mtd-spi-nor-fix-Spansion-regressions-aliased-.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/470-mtd-spi-nor-support-limiting-4K-sectors-support-base.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/475-mtd-spi-nor-Add-Winbond-w25q128jv-support.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/476-mtd-spi-nor-add-eon-en25q128.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/477-mtd-add-spi-nor-add-mx25u3235f.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/479-mtd-spi-nor-add-eon-en25qh64.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/479-mtd-spi-nor-add-xtx-xt25f128b.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/480-mtd-set-rootfs-to-be-root-dev.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/491-ubi-auto-create-ubiblock-device-for-rootfs.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/494-mtd-ubi-add-EOF-marker-support.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/495-mtd-core-add-get_mtd_device_by_node.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/530-jffs2_make_lzma_available.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/532-jffs2_eofdetect.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/553-ubifs-Add-option-to-create-UBI-FS-version-4-on-empty.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/600-netfilter_conntrack_flush.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/610-netfilter_match_bypass_default_checks.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/611-netfilter_match_bypass_default_table.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/612-netfilter_match_reduce_memory_access.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/613-netfilter_optional_tcp_window_check.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/616-net_optimize_xfrm_calls.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/620-net_sched-codel-do-not-defer-queue-length-update.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/630-packet_socket_type.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/640-netfilter-nf_flow_table-add-hardware-offload-support.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/641-netfilter-nf_flow_table-support-hw-offload-through-v.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/642-net-8021q-support-hardware-flow-table-offload.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/643-net-bridge-support-hardware-flow-table-offload.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/644-net-pppoe-support-hardware-flow-table-offload.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/645-netfilter-nf_flow_table-rework-hardware-offload-time.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/646-netfilter-nf_flow_table-rework-private-driver-data.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/655-increase_skb_pad.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/680-NET-skip-GRO-for-foreign-MAC-addresses.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/681-NET-add-of_get_mac_address_mtd.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/703-phy-add-detach-callback-to-struct-phy_driver.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/735-net-phy-at803x-fix-at8033-sgmii-mode.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/739-net-avoid-tx-fault-with-Nokia-GPON-module.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/740-net-sfp-remove-incomplete-100BASE-FX-and-100BASE-LX-.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/741-net-sfp-derive-interface-mode-from-ethtool-link-mode.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/742-net-sfp-add-more-extended-compliance-codes.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/743-net-sfp-add-module-start-stop-upstream-notifications.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/744-net-sfp-move-phy_start-phy_stop-to-phylink.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/745-net-mdio-i2c-add-support-for-Clause-45-accesses.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/746-net-phylink-re-split-__phylink_connect_phy.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/747-net-phylink-support-Clause-45-PHYs-on-SFP-modules.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/748-net-phylink-split-link_an_mode-configured-and-curren.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/749-net-phylink-split-phylink_sfp_module_insert.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/750-net-phylink-delay-MAC-configuration-for-copper-SFP-m.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/751-net-phylink-make-Broadcom-BCM84881-based-SFPs-work.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/752-net-phy-add-Broadcom-BCM84881-PHY-driver.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/753-net-sfp-add-support-for-Clause-45-PHYs.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/754-net-sfp-fix-unbind.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/755-net-sfp-fix-hwmon.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/756-net-sfp-use-a-definition-for-the-fault-recovery-atte.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/757-net-sfp-rename-sm_retries.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/758-net-sfp-error-handling-for-phy-probe.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/759-net-sfp-re-attempt-probing-for-phy.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/810-pci_disable_common_quirks.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/811-pci_disable_usb_common_quirks.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/834-ledtrig-libata.patch [new file with mode: 0644]
target/linux/generic/pending-5.4/920-mangle_bootargs.patch [new file with mode: 0644]

diff --git a/target/linux/generic/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch b/target/linux/generic/backport-5.4/010-Kbuild-don-t-hardcode-path-to-awk-in-scripts-ld-vers.patch
new file mode 100644 (file)
index 0000000..7ac4f9d
--- /dev/null
@@ -0,0 +1,30 @@
+From 13b1ecc3401653a355798eb1dee10cc1608202f4 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 18 Jan 2016 12:27:49 +0100
+Subject: [PATCH 33/34] Kbuild: don't hardcode path to awk in
+ scripts/ld-version.sh
+
+On some systems /usr/bin/awk does not exist, or is broken. Find it via
+$PATH instead.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ scripts/ld-version.sh | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/scripts/ld-version.sh
++++ b/scripts/ld-version.sh
+@@ -1,6 +1,7 @@
+-#!/usr/bin/awk -f
++#!/bin/sh
+ # SPDX-License-Identifier: GPL-2.0
+ # extract linker version number from stdin and turn into single number
++exec awk '
+       {
+       gsub(".*\\)", "");
+       gsub(".*version ", "");
+@@ -9,3 +10,4 @@
+       print a[1]*100000000 + a[2]*1000000 + a[3]*10000;
+       exit
+       }
++'
diff --git a/target/linux/generic/backport-5.4/011-kbuild-export-SUBARCH.patch b/target/linux/generic/backport-5.4/011-kbuild-export-SUBARCH.patch
new file mode 100644 (file)
index 0000000..a42c720
--- /dev/null
@@ -0,0 +1,23 @@
+From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 9 Jul 2017 00:26:53 +0200
+Subject: [PATCH 34/34] kernel: add compile fix for linux 4.9 on x86
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+ Makefile | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -432,8 +432,8 @@ KBUILD_LDFLAGS :=
+ GCC_PLUGINS_CFLAGS :=
+ CLANG_FLAGS :=
+-export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC
+-export CPP AR NM STRIP OBJCOPY OBJDUMP KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS
++export ARCH SRCARCH SUBARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD
++export CC CPP AR NM STRIP OBJCOPY OBJDUMP KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS
+ export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE
+ export HOSTCXX KBUILD_HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
diff --git a/target/linux/generic/backport-5.4/020-backport_netfilter_rtcache.patch b/target/linux/generic/backport-5.4/020-backport_netfilter_rtcache.patch
new file mode 100644 (file)
index 0000000..c02b8f3
--- /dev/null
@@ -0,0 +1,558 @@
+From 1bb0c3ec899827cfa4668bb63a08713a40744d21 Mon Sep 17 00:00:00 2001
+From: Florian Westphal <fw@strlen.de>
+Date: Sun, 9 Jul 2017 08:58:30 +0200
+Subject: [PATCH] netfilter: conntrack: cache route for forwarded connections
+
+... to avoid per-packet FIB lookup if possible.
+
+The cached dst is re-used provided the input interface
+is the same as that of the previous packet in the same direction.
+
+If not, the cached dst is invalidated.
+
+For ipv6 we also need to store sernum, else dst_check doesn't work,
+pointed out by Eric Dumazet.
+
+This should speed up forwarding when conntrack is already in use
+anyway, especially when using reverse path filtering -- active RPF
+enforces two FIB lookups for each packet.
+
+Before the routing cache removal this didn't matter since RPF was performed
+only when route cache didn't yield a result; but without route cache it
+comes at higher price.
+
+Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
+avoid holding on to dsts of 'frozen' conntracks.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+---
+ include/net/netfilter/nf_conntrack_extend.h  |   4 +
+ include/net/netfilter/nf_conntrack_rtcache.h |  34 +++
+ net/netfilter/Kconfig                        |  12 +
+ net/netfilter/Makefile                       |   3 +
+ net/netfilter/nf_conntrack_rtcache.c         | 428 +++++++++++++++++++++++++++
+ 5 files changed, 481 insertions(+)
+ create mode 100644 include/net/netfilter/nf_conntrack_rtcache.h
+ create mode 100644 net/netfilter/nf_conntrack_rtcache.c
+
+--- a/include/net/netfilter/nf_conntrack_extend.h
++++ b/include/net/netfilter/nf_conntrack_extend.h
+@@ -28,6 +28,9 @@ enum nf_ct_ext_id {
+ #if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
+       NF_CT_EXT_SYNPROXY,
+ #endif
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++      NF_CT_EXT_RTCACHE,
++#endif
+       NF_CT_EXT_NUM,
+ };
+@@ -40,6 +43,7 @@ enum nf_ct_ext_id {
+ #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
+ #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
+ #define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
++#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
+ /* Extensions: optional stuff which isn't permanently in struct. */
+ struct nf_ct_ext {
+--- /dev/null
++++ b/include/net/netfilter/nf_conntrack_rtcache.h
+@@ -0,0 +1,34 @@
++#include <linux/gfp.h>
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++
++struct dst_entry;
++
++struct nf_conn_dst_cache {
++      struct dst_entry *dst;
++      int iif;
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++      u32 cookie;
++#endif
++
++};
++
++struct nf_conn_rtcache {
++      struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
++};
++
++static inline
++struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
++      return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
++#else
++      return NULL;
++#endif
++}
++
++static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
++                                        enum ip_conntrack_dir dir)
++{
++      return rtc->cached_dst[dir].iif;
++}
+--- a/net/netfilter/Kconfig
++++ b/net/netfilter/Kconfig
+@@ -135,6 +135,18 @@ config NF_CONNTRACK_EVENTS
+         If unsure, say `N'.
++config NF_CONNTRACK_RTCACHE
++      tristate "Cache route entries in conntrack objects"
++      depends on NETFILTER_ADVANCED
++      depends on NF_CONNTRACK
++      help
++        If this option is enabled, the connection tracking code will
++        cache routing information for each connection that is being
++        forwarded, at a cost of 32 bytes per conntrack object.
++
++        To compile it as a module, choose M here.  If unsure, say N.
++        The module will be called nf_conntrack_rtcache.
++
+ config NF_CONNTRACK_TIMEOUT
+       bool  'Connection tracking timeout'
+       depends on NETFILTER_ADVANCED
+--- a/net/netfilter/Makefile
++++ b/net/netfilter/Makefile
+@@ -25,6 +25,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_OSF) += n
+ # connection tracking
+ obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
++# optional conntrack route cache extension
++obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
++
+ obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
+ # netlink interface for nf_conntrack
+--- /dev/null
++++ b/net/netfilter/nf_conntrack_rtcache.c
+@@ -0,0 +1,428 @@
++/* route cache for netfilter.
++ *
++ * (C) 2014 Red Hat GmbH
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#include <linux/types.h>
++#include <linux/netfilter.h>
++#include <linux/skbuff.h>
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/export.h>
++#include <linux/module.h>
++
++#include <net/dst.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++#include <net/netfilter/nf_conntrack_extend.h>
++#include <net/netfilter/nf_conntrack_rtcache.h>
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++#include <net/ip6_fib.h>
++#endif
++
++static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
++                                    enum ip_conntrack_dir dir)
++{
++      struct dst_entry *dst = rtc->cached_dst[dir].dst;
++
++      dst_release(dst);
++}
++
++static void nf_conn_rtcache_destroy(struct nf_conn *ct)
++{
++      struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++      if (!rtc)
++              return;
++
++      __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
++      __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
++}
++
++static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
++{
++      struct nf_conn_rtcache *rtc;
++
++      rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
++      if (rtc) {
++              rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
++              rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
++              rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
++              rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
++      }
++}
++
++static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
++{
++      return nf_ct_rtcache_find(ct);
++}
++
++static struct dst_entry *
++nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
++                      enum ip_conntrack_dir dir)
++{
++      return rtc->cached_dst[dir].dst;
++}
++
++static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
++{
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++      if (pf == NFPROTO_IPV6) {
++              const struct rt6_info *rt = (const struct rt6_info *)dst;
++
++              if (rt->from && rt->from->fib6_node)
++                      return (u32)rt->from->fib6_node->fn_sernum;
++      }
++#endif
++      return 0;
++}
++
++static void nf_conn_rtcache_dst_set(int pf,
++                                  struct nf_conn_rtcache *rtc,
++                                  struct dst_entry *dst,
++                                  enum ip_conntrack_dir dir, int iif)
++{
++      if (rtc->cached_dst[dir].iif != iif)
++              rtc->cached_dst[dir].iif = iif;
++
++      if (rtc->cached_dst[dir].dst != dst) {
++              struct dst_entry *old;
++
++              dst_hold(dst);
++
++              old = xchg(&rtc->cached_dst[dir].dst, dst);
++              dst_release(old);
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++              if (pf == NFPROTO_IPV6)
++                      rtc->cached_dst[dir].cookie =
++                              nf_rtcache_get_cookie(pf, dst);
++#endif
++      }
++}
++
++static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
++                                       enum ip_conntrack_dir dir)
++{
++      struct dst_entry *old;
++
++      pr_debug("Invalidate iif %d for dir %d on cache %p\n",
++               rtc->cached_dst[dir].iif, dir, rtc);
++
++      old = xchg(&rtc->cached_dst[dir].dst, NULL);
++      dst_release(old);
++      rtc->cached_dst[dir].iif = -1;
++}
++
++static unsigned int nf_rtcache_in(u_int8_t pf,
++                                struct sk_buff *skb,
++                                const struct nf_hook_state *state)
++{
++      struct nf_conn_rtcache *rtc;
++      enum ip_conntrack_info ctinfo;
++      enum ip_conntrack_dir dir;
++      struct dst_entry *dst;
++      struct nf_conn *ct;
++      int iif;
++      u32 cookie;
++
++      if (skb_dst(skb) || skb->sk)
++              return NF_ACCEPT;
++
++      ct = nf_ct_get(skb, &ctinfo);
++      if (!ct)
++              return NF_ACCEPT;
++
++      rtc = nf_ct_rtcache_find_usable(ct);
++      if (!rtc)
++              return NF_ACCEPT;
++
++      /* if iif changes, don't use cache and let ip stack
++       * do route lookup.
++       *
++       * If rp_filter is enabled it might toss skb, so
++       * we don't want to avoid these checks.
++       */
++      dir = CTINFO2DIR(ctinfo);
++      iif = nf_conn_rtcache_iif_get(rtc, dir);
++      if (state->in->ifindex != iif) {
++              pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
++                       ct, iif, state->in->ifindex);
++              return NF_ACCEPT;
++      }
++      dst = nf_conn_rtcache_dst_get(rtc, dir);
++      if (dst == NULL)
++              return NF_ACCEPT;
++
++      cookie = nf_rtcache_get_cookie(pf, dst);
++
++      dst = dst_check(dst, cookie);
++      pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
++      if (likely(dst))
++              skb_dst_set_noref(skb, dst);
++      else
++              nf_conn_rtcache_dst_obsolete(rtc, dir);
++
++      return NF_ACCEPT;
++}
++
++static unsigned int nf_rtcache_forward(u_int8_t pf,
++                                     struct sk_buff *skb,
++                                     const struct nf_hook_state *state)
++{
++      struct nf_conn_rtcache *rtc;
++      enum ip_conntrack_info ctinfo;
++      enum ip_conntrack_dir dir;
++      struct nf_conn *ct;
++      struct dst_entry *dst = skb_dst(skb);
++      int iif;
++
++      ct = nf_ct_get(skb, &ctinfo);
++      if (!ct)
++              return NF_ACCEPT;
++
++      if (dst && dst_xfrm(dst))
++              return NF_ACCEPT;
++
++      if (!nf_ct_is_confirmed(ct)) {
++              if (WARN_ON(nf_ct_rtcache_find(ct)))
++                      return NF_ACCEPT;
++              nf_ct_rtcache_ext_add(ct);
++              return NF_ACCEPT;
++      }
++
++      rtc = nf_ct_rtcache_find_usable(ct);
++      if (!rtc)
++              return NF_ACCEPT;
++
++      dir = CTINFO2DIR(ctinfo);
++      iif = nf_conn_rtcache_iif_get(rtc, dir);
++      pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
++               ct, skb, dir, iif, state->in->ifindex);
++      if (likely(state->in->ifindex == iif))
++              return NF_ACCEPT;
++
++      nf_conn_rtcache_dst_set(pf, rtc, skb_dst(skb), dir, state->in->ifindex);
++      return NF_ACCEPT;
++}
++
++static unsigned int nf_rtcache_in4(void *priv,
++                                struct sk_buff *skb,
++                                const struct nf_hook_state *state)
++{
++      return nf_rtcache_in(NFPROTO_IPV4, skb, state);
++}
++
++static unsigned int nf_rtcache_forward4(void *priv,
++                                     struct sk_buff *skb,
++                                     const struct nf_hook_state *state)
++{
++      return nf_rtcache_forward(NFPROTO_IPV4, skb, state);
++}
++
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++static unsigned int nf_rtcache_in6(void *priv,
++                                struct sk_buff *skb,
++                                const struct nf_hook_state *state)
++{
++      return nf_rtcache_in(NFPROTO_IPV6, skb, state);
++}
++
++static unsigned int nf_rtcache_forward6(void *priv,
++                                     struct sk_buff *skb,
++                                     const struct nf_hook_state *state)
++{
++      return nf_rtcache_forward(NFPROTO_IPV6, skb, state);
++}
++#endif
++
++static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
++{
++      struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++      struct net_device *dev = data;
++
++      if (!rtc)
++              return 0;
++
++      if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
++          dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
++              nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
++              nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
++      }
++
++      return 0;
++}
++
++static int nf_rtcache_netdev_event(struct notifier_block *this,
++                                 unsigned long event, void *ptr)
++{
++      struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++      struct net *net = dev_net(dev);
++
++      if (event == NETDEV_DOWN)
++              nf_ct_iterate_cleanup_net(net, nf_rtcache_dst_remove, dev, 0, 0);
++
++      return NOTIFY_DONE;
++}
++
++static struct notifier_block nf_rtcache_notifier = {
++      .notifier_call = nf_rtcache_netdev_event,
++};
++
++static struct nf_hook_ops rtcache_ops[] = {
++      {
++              .hook           = nf_rtcache_in4,
++              .pf             = NFPROTO_IPV4,
++              .hooknum        = NF_INET_PRE_ROUTING,
++              .priority       = NF_IP_PRI_LAST,
++      },
++      {
++              .hook           = nf_rtcache_forward4,
++              .pf             = NFPROTO_IPV4,
++              .hooknum        = NF_INET_FORWARD,
++              .priority       = NF_IP_PRI_LAST,
++      },
++#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
++      {
++              .hook           = nf_rtcache_in6,
++              .pf             = NFPROTO_IPV6,
++              .hooknum        = NF_INET_PRE_ROUTING,
++              .priority       = NF_IP_PRI_LAST,
++      },
++      {
++              .hook           = nf_rtcache_forward6,
++              .pf             = NFPROTO_IPV6,
++              .hooknum        = NF_INET_FORWARD,
++              .priority       = NF_IP_PRI_LAST,
++      },
++#endif
++};
++
++static struct nf_ct_ext_type rtcache_extend __read_mostly = {
++      .len    = sizeof(struct nf_conn_rtcache),
++      .align  = __alignof__(struct nf_conn_rtcache),
++      .id     = NF_CT_EXT_RTCACHE,
++      .destroy = nf_conn_rtcache_destroy,
++};
++
++static int __net_init rtcache_net_init(struct net *net)
++{
++      return nf_register_net_hooks(net, rtcache_ops, ARRAY_SIZE(rtcache_ops));
++}
++
++static void __net_exit rtcache_net_exit(struct net *net)
++{
++      /* remove hooks so no new connections get rtcache extension */
++      nf_unregister_net_hooks(net, rtcache_ops, ARRAY_SIZE(rtcache_ops));
++}
++
++static struct pernet_operations rtcache_ops_net_ops = {
++      .init   = rtcache_net_init,
++      .exit   = rtcache_net_exit,
++};
++
++static int __init nf_conntrack_rtcache_init(void)
++{
++      int ret = nf_ct_extend_register(&rtcache_extend);
++
++      if (ret < 0) {
++              pr_err("nf_conntrack_rtcache: Unable to register extension\n");
++              return ret;
++      }
++
++      ret = register_pernet_subsys(&rtcache_ops_net_ops);
++      if (ret) {
++              nf_ct_extend_unregister(&rtcache_extend);
++              return ret;
++      }
++
++      ret = register_netdevice_notifier(&nf_rtcache_notifier);
++      if (ret) {
++              nf_ct_extend_unregister(&rtcache_extend);
++              unregister_pernet_subsys(&rtcache_ops_net_ops);
++      }
++
++      return ret;
++}
++
++static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
++{
++      struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
++
++      return rtc != NULL;
++}
++
++static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
++{
++      bool wait = false;
++      int cpu;
++
++      for_each_possible_cpu(cpu) {
++              struct nf_conntrack_tuple_hash *h;
++              struct hlist_nulls_node *n;
++              struct nf_conn *ct;
++              struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
++
++              rcu_read_lock();
++              spin_lock_bh(&pcpu->lock);
++
++              hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
++                      ct = nf_ct_tuplehash_to_ctrack(h);
++                      if (nf_ct_rtcache_find(ct) != NULL) {
++                              wait = true;
++                              break;
++                      }
++              }
++              spin_unlock_bh(&pcpu->lock);
++              rcu_read_unlock();
++      }
++
++      return wait;
++}
++
++static void __exit nf_conntrack_rtcache_fini(void)
++{
++      struct net *net;
++      int count = 0;
++
++      synchronize_net();
++
++      unregister_netdevice_notifier(&nf_rtcache_notifier);
++      unregister_pernet_subsys(&rtcache_ops_net_ops);
++
++      synchronize_net();
++
++      rtnl_lock();
++
++      /* zap all conntracks with rtcache extension */
++      for_each_net(net)
++              nf_ct_iterate_cleanup_net(net, nf_rtcache_ext_remove, NULL, 0, 0);
++
++      for_each_net(net) {
++              /* .. and make sure they're gone from dying list, too */
++              while (nf_conntrack_rtcache_wait_for_dying(net)) {
++                      msleep(200);
++                      WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
++              }
++      }
++
++      rtnl_unlock();
++
++      synchronize_net();
++      nf_ct_extend_unregister(&rtcache_extend);
++}
++module_init(nf_conntrack_rtcache_init);
++module_exit(nf_conntrack_rtcache_fini);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
++MODULE_DESCRIPTION("Conntrack route cache extension");
diff --git a/target/linux/generic/backport-5.4/047-v4.21-mtd-keep-original-flags-for-every-struct-mtd_info.patch b/target/linux/generic/backport-5.4/047-v4.21-mtd-keep-original-flags-for-every-struct-mtd_info.patch
new file mode 100644 (file)
index 0000000..d587c9e
--- /dev/null
@@ -0,0 +1,58 @@
+From 1186af457cc186c5ed01708da71b1ffbdf0a2638 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 20 Nov 2018 09:55:45 +0100
+Subject: [PATCH] mtd: keep original flags for every struct mtd_info
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When allocating a new partition mtd subsystem runs internal tests in the
+allocate_partition(). They may result in modifying specified flags (e.g.
+dropping some /features/ like write access).
+
+Those constraints don't have to be necessary true for subpartitions. It
+may happen parent partition isn't block aligned (effectively disabling
+write access) while subpartition may fit blocks nicely. In such case all
+checks should be run again (starting with original flags value).
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/mtd/mtdcore.c   | 2 ++
+ drivers/mtd/mtdpart.c   | 3 ++-
+ include/linux/mtd/mtd.h | 1 +
+ 3 files changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -665,6 +665,8 @@ static void mtd_set_dev_defaults(struct
+       } else {
+               pr_debug("mtd device won't show a device symlink in sysfs\n");
+       }
++
++      mtd->orig_flags = mtd->flags;
+ }
+ /**
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -346,7 +346,8 @@ static struct mtd_part *allocate_partiti
+       /* set up the MTD object for this partition */
+       slave->mtd.type = parent->type;
+-      slave->mtd.flags = parent->flags & ~part->mask_flags;
++      slave->mtd.flags = parent->orig_flags & ~part->mask_flags;
++      slave->mtd.orig_flags = slave->mtd.flags;
+       slave->mtd.size = part->size;
+       slave->mtd.writesize = parent->writesize;
+       slave->mtd.writebufsize = parent->writebufsize;
+--- a/include/linux/mtd/mtd.h
++++ b/include/linux/mtd/mtd.h
+@@ -207,6 +207,7 @@ struct mtd_debug_info {
+ struct mtd_info {
+       u_char type;
+       uint32_t flags;
++      uint32_t orig_flags; /* Flags as before running mtd checks */
+       uint64_t size;   // Total size of the MTD
+       /* "Major" erase size for the device. Naïve users may take this
diff --git a/target/linux/generic/backport-5.4/048-v4.21-mtd-improve-calculating-partition-boundaries-when-ch.patch b/target/linux/generic/backport-5.4/048-v4.21-mtd-improve-calculating-partition-boundaries-when-ch.patch
new file mode 100644 (file)
index 0000000..0229627
--- /dev/null
@@ -0,0 +1,55 @@
+From 6750f61a13a0197c40e4a40739117493b15f19e8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Tue, 20 Nov 2018 10:24:09 +0100
+Subject: [PATCH] mtd: improve calculating partition boundaries when checking
+ for alignment
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When checking for alignment mtd should check absolute offsets. It's
+important for subpartitions as it doesn't make sense to check their
+relative addresses.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/mtd/mtdpart.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -61,6 +61,15 @@ static inline struct mtd_part *mtd_to_pa
+       return container_of(mtd, struct mtd_part, mtd);
+ }
++static u64 part_absolute_offset(struct mtd_info *mtd)
++{
++      struct mtd_part *part = mtd_to_part(mtd);
++
++      if (!mtd_is_partition(mtd))
++              return 0;
++
++      return part_absolute_offset(part->parent) + part->offset;
++}
+ /*
+  * MTD methods which simply translate the effective address and pass through
+@@ -518,7 +527,7 @@ static struct mtd_part *allocate_partiti
+       if (!(slave->mtd.flags & MTD_NO_ERASE))
+               wr_alignment = slave->mtd.erasesize;
+-      tmp = slave->offset;
++      tmp = part_absolute_offset(parent) + slave->offset;
+       remainder = do_div(tmp, wr_alignment);
+       if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
+               /* Doesn't start on a boundary of major erase size */
+@@ -529,7 +538,7 @@ static struct mtd_part *allocate_partiti
+                       part->name);
+       }
+-      tmp = slave->mtd.size;
++      tmp = part_absolute_offset(parent) + slave->mtd.size;
+       remainder = do_div(tmp, wr_alignment);
+       if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
+               slave->mtd.flags &= ~MTD_WRITEABLE;
diff --git a/target/linux/generic/backport-5.4/080-v5.1-0001-bcma-keep-a-direct-pointer-to-the-struct-device.patch b/target/linux/generic/backport-5.4/080-v5.1-0001-bcma-keep-a-direct-pointer-to-the-struct-device.patch
new file mode 100644 (file)
index 0000000..cc32aee
--- /dev/null
@@ -0,0 +1,199 @@
+From 5a1c18b761ddb299a06746948b9ec2814b04fa92 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 2 Jan 2019 00:00:01 +0100
+Subject: [PATCH] bcma: keep a direct pointer to the struct device
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Accessing struct device is pretty useful/common so having a direct
+pointer:
+1) Simplifies some code
+2) Makes bcma_bus_get_host_dev() unneeded
+3) Allows further improvements like using dev_* printing helpers
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/bcma/bcma_private.h |  1 -
+ drivers/bcma/driver_gpio.c  |  2 +-
+ drivers/bcma/host_pci.c     |  2 ++
+ drivers/bcma/host_soc.c     |  4 ++--
+ drivers/bcma/main.c         | 45 +++++++++----------------------------
+ include/linux/bcma/bcma.h   | 11 +++------
+ 6 files changed, 18 insertions(+), 47 deletions(-)
+
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -33,7 +33,6 @@ int __init bcma_bus_early_register(struc
+ int bcma_bus_suspend(struct bcma_bus *bus);
+ int bcma_bus_resume(struct bcma_bus *bus);
+ #endif
+-struct device *bcma_bus_get_host_dev(struct bcma_bus *bus);
+ /* scan.c */
+ void bcma_detect_chip(struct bcma_bus *bus);
+--- a/drivers/bcma/driver_gpio.c
++++ b/drivers/bcma/driver_gpio.c
+@@ -183,7 +183,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
+       chip->direction_input   = bcma_gpio_direction_input;
+       chip->direction_output  = bcma_gpio_direction_output;
+       chip->owner             = THIS_MODULE;
+-      chip->parent            = bcma_bus_get_host_dev(bus);
++      chip->parent            = bus->dev;
+ #if IS_BUILTIN(CONFIG_OF)
+       chip->of_node           = cc->core->dev.of_node;
+ #endif
+--- a/drivers/bcma/host_pci.c
++++ b/drivers/bcma/host_pci.c
+@@ -196,6 +196,8 @@ static int bcma_host_pci_probe(struct pc
+               goto err_pci_release_regions;
+       }
++      bus->dev = &dev->dev;
++
+       /* Map MMIO */
+       err = -ENOMEM;
+       bus->mmio = pci_iomap(dev, 0, ~0UL);
+--- a/drivers/bcma/host_soc.c
++++ b/drivers/bcma/host_soc.c
+@@ -179,7 +179,6 @@ int __init bcma_host_soc_register(struct
+       /* Host specific */
+       bus->hosttype = BCMA_HOSTTYPE_SOC;
+       bus->ops = &bcma_host_soc_ops;
+-      bus->host_pdev = NULL;
+       /* Initialize struct, detect chip */
+       bcma_init_bus(bus);
+@@ -213,6 +212,8 @@ static int bcma_host_soc_probe(struct pl
+       if (!bus)
+               return -ENOMEM;
++      bus->dev = dev;
++
+       /* Map MMIO */
+       bus->mmio = of_iomap(np, 0);
+       if (!bus->mmio)
+@@ -221,7 +222,6 @@ static int bcma_host_soc_probe(struct pl
+       /* Host specific */
+       bus->hosttype = BCMA_HOSTTYPE_SOC;
+       bus->ops = &bcma_host_soc_ops;
+-      bus->host_pdev = pdev;
+       /* Initialize struct, detect chip */
+       bcma_init_bus(bus);
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -223,8 +223,8 @@ unsigned int bcma_core_irq(struct bcma_d
+                       mips_irq = bcma_core_mips_irq(core);
+                       return mips_irq <= 4 ? mips_irq + 2 : 0;
+               }
+-              if (bus->host_pdev)
+-                      return bcma_of_get_irq(&bus->host_pdev->dev, core, num);
++              if (bus->dev)
++                      return bcma_of_get_irq(bus->dev, core, num);
+               return 0;
+       case BCMA_HOSTTYPE_SDIO:
+               return 0;
+@@ -239,18 +239,18 @@ void bcma_prepare_core(struct bcma_bus *
+       core->dev.release = bcma_release_core_dev;
+       core->dev.bus = &bcma_bus_type;
+       dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
+-      core->dev.parent = bcma_bus_get_host_dev(bus);
+-      if (core->dev.parent)
+-              bcma_of_fill_device(core->dev.parent, core);
++      core->dev.parent = bus->dev;
++      if (bus->dev)
++              bcma_of_fill_device(bus->dev, core);
+       switch (bus->hosttype) {
+       case BCMA_HOSTTYPE_PCI:
+-              core->dma_dev = &bus->host_pci->dev;
++              core->dma_dev = bus->dev;
+               core->irq = bus->host_pci->irq;
+               break;
+       case BCMA_HOSTTYPE_SOC:
+-              if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) {
+-                      core->dma_dev = &bus->host_pdev->dev;
++              if (IS_ENABLED(CONFIG_OF) && bus->dev) {
++                      core->dma_dev = bus->dev;
+               } else {
+                       core->dev.dma_mask = &core->dev.coherent_dma_mask;
+                       core->dma_dev = &core->dev;
+@@ -261,28 +261,6 @@ void bcma_prepare_core(struct bcma_bus *
+       }
+ }
+-struct device *bcma_bus_get_host_dev(struct bcma_bus *bus)
+-{
+-      switch (bus->hosttype) {
+-      case BCMA_HOSTTYPE_PCI:
+-              if (bus->host_pci)
+-                      return &bus->host_pci->dev;
+-              else
+-                      return NULL;
+-      case BCMA_HOSTTYPE_SOC:
+-              if (bus->host_pdev)
+-                      return &bus->host_pdev->dev;
+-              else
+-                      return NULL;
+-      case BCMA_HOSTTYPE_SDIO:
+-              if (bus->host_sdio)
+-                      return &bus->host_sdio->dev;
+-              else
+-                      return NULL;
+-      }
+-      return NULL;
+-}
+-
+ void bcma_init_bus(struct bcma_bus *bus)
+ {
+       mutex_lock(&bcma_buses_mutex);
+@@ -402,7 +380,6 @@ int bcma_bus_register(struct bcma_bus *b
+ {
+       int err;
+       struct bcma_device *core;
+-      struct device *dev;
+       /* Scan for devices (cores) */
+       err = bcma_bus_scan(bus);
+@@ -425,10 +402,8 @@ int bcma_bus_register(struct bcma_bus *b
+               bcma_core_pci_early_init(&bus->drv_pci[0]);
+       }
+-      dev = bcma_bus_get_host_dev(bus);
+-      if (dev) {
+-              of_platform_default_populate(dev->of_node, NULL, dev);
+-      }
++      if (bus->dev)
++              of_platform_default_populate(bus->dev->of_node, NULL, bus->dev);
+       /* Cores providing flash access go before SPROM init */
+       list_for_each_entry(core, &bus->cores, list) {
+--- a/include/linux/bcma/bcma.h
++++ b/include/linux/bcma/bcma.h
+@@ -332,6 +332,8 @@ extern int bcma_arch_register_fallback_s
+               struct ssb_sprom *out));
+ struct bcma_bus {
++      struct device *dev;
++
+       /* The MMIO area. */
+       void __iomem *mmio;
+@@ -339,14 +341,7 @@ struct bcma_bus {
+       enum bcma_hosttype hosttype;
+       bool host_is_pcie2; /* Used for BCMA_HOSTTYPE_PCI only */
+-      union {
+-              /* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */
+-              struct pci_dev *host_pci;
+-              /* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
+-              struct sdio_func *host_sdio;
+-              /* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
+-              struct platform_device *host_pdev;
+-      };
++      struct pci_dev *host_pci; /* PCI bus pointer (BCMA_HOSTTYPE_PCI only) */
+       struct bcma_chipinfo chipinfo;
diff --git a/target/linux/generic/backport-5.4/080-v5.1-0002-bcma-use-dev_-printing-functions.patch b/target/linux/generic/backport-5.4/080-v5.1-0002-bcma-use-dev_-printing-functions.patch
new file mode 100644 (file)
index 0000000..7ce8ba8
--- /dev/null
@@ -0,0 +1,36 @@
+From 777bc4801a6868fcbff09ffb6e30f023e7c5ed38 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 2 Jan 2019 00:00:02 +0100
+Subject: [PATCH] bcma: use dev_* printing functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It provides more meaningful messages.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+---
+ drivers/bcma/bcma_private.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/bcma/bcma_private.h
++++ b/drivers/bcma/bcma_private.h
+@@ -10,13 +10,13 @@
+ #include <linux/delay.h>
+ #define bcma_err(bus, fmt, ...) \
+-      pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
++      dev_err((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
+ #define bcma_warn(bus, fmt, ...) \
+-      pr_warn("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
++      dev_warn((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
+ #define bcma_info(bus, fmt, ...) \
+-      pr_info("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
++      dev_info((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
+ #define bcma_debug(bus, fmt, ...) \
+-      pr_debug("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
++      dev_dbg((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
+ struct bcma_bus;
diff --git a/target/linux/generic/backport-5.4/095-Allow-class-e-address-assignment-via-ifconfig-ioctl.patch b/target/linux/generic/backport-5.4/095-Allow-class-e-address-assignment-via-ifconfig-ioctl.patch
new file mode 100644 (file)
index 0000000..bf6d9ac
--- /dev/null
@@ -0,0 +1,79 @@
+From 46bf067870156abd61fe24d14c2486d15b8b502c Mon Sep 17 00:00:00 2001
+From: Dave Taht <dave@taht.net>
+Date: Fri, 14 Dec 2018 18:38:40 +0000
+Subject: [PATCH 1/1] Allow class-e address assignment in ifconfig and early
+ boot
+
+While the linux kernel became mostly "class-e clean" a decade ago,
+and most distributions long ago switched to the iproute2 suite
+of utilities, which allow class-e (240.0.0.0/4) address assignment,
+distributions relying on busybox, toybox and other forms of
+ifconfig cannot assign class-e addresses without this kernel patch.
+
+With this patch, also, a boot command line on these addresses is feasible:
+(ip=248.0.1.2::248.0.1.1:255.255.255.0).
+
+While CIDR has been obsolete for 2 decades, and a survey of all the
+userspace open source code in the world shows most IN_whatever macros
+are also obsolete... rather than obsolete CIDR from this ioctl entirely,
+this patch merely enables class-e assignment, sanely.
+
+H/T to Vince Fuller and his original patch here:
+    https://lkml.org/lkml/2008/1/7/370
+
+Signed-off-by: Dave Taht <dave.taht@gmail.com>
+Reviewed-by: John Gilmore <gnu@toad.com>
+---
+ include/uapi/linux/in.h | 8 ++++++--
+ net/ipv4/devinet.c      | 4 +++-
+ net/ipv4/ipconfig.c     | 2 ++
+ 3 files changed, 11 insertions(+), 3 deletions(-)
+
+--- a/include/uapi/linux/in.h
++++ b/include/uapi/linux/in.h
+@@ -268,8 +268,12 @@ struct sockaddr_in {
+ #define       IN_MULTICAST(a)         IN_CLASSD(a)
+ #define IN_MULTICAST_NET      0xF0000000
+-#define       IN_EXPERIMENTAL(a)      ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+-#define       IN_BADCLASS(a)          IN_EXPERIMENTAL((a))
++#define       IN_BADCLASS(a)          (((long int) (a) ) == (long int)0xffffffff)
++#define       IN_EXPERIMENTAL(a)      IN_BADCLASS((a))
++
++#define       IN_CLASSE(a)            ((((long int) (a)) & 0xf0000000) == 0xf0000000)
++#define       IN_CLASSE_NET           0xffffffff
++#define       IN_CLASSE_NSHIFT        0
+ /* Address to accept any incoming messages. */
+ #define       INADDR_ANY              ((unsigned long int) 0x00000000)
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -949,7 +949,7 @@ static int inet_abc_len(__be32 addr)
+ {
+       int rc = -1;    /* Something else, probably a multicast. */
+-      if (ipv4_is_zeronet(addr))
++      if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
+               rc = 0;
+       else {
+               __u32 haddr = ntohl(addr);
+@@ -960,6 +960,8 @@ static int inet_abc_len(__be32 addr)
+                       rc = 16;
+               else if (IN_CLASSC(haddr))
+                       rc = 24;
++              else if (IN_CLASSE(haddr))
++                      rc = 32;
+       }
+       return rc;
+--- a/net/ipv4/ipconfig.c
++++ b/net/ipv4/ipconfig.c
+@@ -429,6 +429,8 @@ static int __init ic_defaults(void)
+                       ic_netmask = htonl(IN_CLASSB_NET);
+               else if (IN_CLASSC(ntohl(ic_myaddr)))
+                       ic_netmask = htonl(IN_CLASSC_NET);
++              else if (IN_CLASSE(ntohl(ic_myaddr)))
++                      ic_netmask = htonl(IN_CLASSE_NET);
+               else {
+                       pr_err("IP-Config: Unable to guess netmask for address %pI4\n",
+                              &ic_myaddr);
diff --git a/target/linux/generic/backport-5.4/101-arm-cns3xxx-use-actual-size-reads-for-PCIe.patch b/target/linux/generic/backport-5.4/101-arm-cns3xxx-use-actual-size-reads-for-PCIe.patch
new file mode 100644 (file)
index 0000000..2b33843
--- /dev/null
@@ -0,0 +1,46 @@
+From 4cc30de79d293f1e8c5f50ae3a9c005def9564a0 Mon Sep 17 00:00:00 2001
+From: Koen Vandeputte <koen.vandeputte@ncentric.com>
+Date: Mon, 7 Jan 2019 14:14:27 +0100
+Subject: [PATCH 2/2] arm: cns3xxx: use actual size reads for PCIe
+
+commit 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
+reimplemented cns3xxx_pci_read_config() using pci_generic_config_read32(),
+which preserved the property of only doing 32-bit reads.
+
+It also replaced cns3xxx_pci_write_config() with pci_generic_config_write(),
+so it changed writes from always being 32 bits to being the actual size,
+which works just fine.
+
+Due to:
+- The documentation does not mention that only 32 bit access is allowed.
+- Writes are already executed using the actual size
+- Extensive testing shows that 8b, 16b and 32b reads work as intended
+
+It makes perfectly sense to also swap 32 bit reading in favor of actual size.
+
+Fixes: 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
+Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
+CC: Arnd Bergmann <arnd@arndb.de>
+CC: Krzysztof Halasa <khalasa@piap.pl>
+CC: Olof Johansson <olof@lixom.net>
+CC: Robin Leblon <robin.leblon@ncentric.com>
+CC: Rob Herring <robh@kernel.org>
+CC: Russell King <linux@armlinux.org.uk>
+CC: Tim Harvey <tharvey@gateworks.com>
+CC: stable@vger.kernel.org # v4.0+
+---
+ arch/arm/mach-cns3xxx/pcie.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/mach-cns3xxx/pcie.c
++++ b/arch/arm/mach-cns3xxx/pcie.c
+@@ -93,7 +93,7 @@ static int cns3xxx_pci_read_config(struc
+       u32 mask = (0x1ull << (size * 8)) - 1;
+       int shift = (where % 4) * 8;
+-      ret = pci_generic_config_read32(bus, devfn, where, size, val);
++      ret = pci_generic_config_read(bus, devfn, where, size, val);
+       if (ret == PCIBIOS_SUCCESSFUL && !bus->number && !devfn &&
+           (where & 0xffc) == PCI_CLASS_REVISION)
diff --git a/target/linux/generic/backport-5.4/200-v5.2-usb-dwc2-Set-lpm-mode-parameters-depend-on-HW-configuration.patch b/target/linux/generic/backport-5.4/200-v5.2-usb-dwc2-Set-lpm-mode-parameters-depend-on-HW-configuration.patch
new file mode 100644 (file)
index 0000000..ed4aadf
--- /dev/null
@@ -0,0 +1,63 @@
+From 28b5c129ca6e585ec95c160ec4297bc6c6360b6f Mon Sep 17 00:00:00 2001
+From: Minas Harutyunyan <minas.harutyunyan@synopsys.com>
+Date: Mon, 4 Mar 2019 17:08:07 +0400
+Subject: usb: dwc2: Set lpm mode parameters depend on HW configuration
+
+If core not supported lpm, i.e. BCM2835 then confusing warnings seen
+in log.
+
+To avoid these warnings, added function dwc2_set_param_lpm() to set
+lpm and other lpm related parameters based on lpm support by core.
+
+Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
+Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
+---
+ drivers/usb/dwc2/params.c | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+--- a/drivers/usb/dwc2/params.c
++++ b/drivers/usb/dwc2/params.c
+@@ -273,6 +273,23 @@ static void dwc2_set_param_power_down(st
+       hsotg->params.power_down = val;
+ }
++static void dwc2_set_param_lpm(struct dwc2_hsotg *hsotg)
++{
++      struct dwc2_core_params *p = &hsotg->params;
++
++      p->lpm = hsotg->hw_params.lpm_mode;
++      if (p->lpm) {
++              p->lpm_clock_gating = true;
++              p->besl = true;
++              p->hird_threshold_en = true;
++              p->hird_threshold = 4;
++      } else {
++              p->lpm_clock_gating = false;
++              p->besl = false;
++              p->hird_threshold_en = false;
++      }
++}
++
+ /**
+  * dwc2_set_default_params() - Set all core parameters to their
+  * auto-detected default values.
+@@ -291,6 +308,7 @@ static void dwc2_set_default_params(stru
+       dwc2_set_param_speed(hsotg);
+       dwc2_set_param_phy_utmi_width(hsotg);
+       dwc2_set_param_power_down(hsotg);
++      dwc2_set_param_lpm(hsotg);
+       p->phy_ulpi_ddr = false;
+       p->phy_ulpi_ext_vbus = false;
+@@ -303,11 +321,6 @@ static void dwc2_set_default_params(stru
+       p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a);
+       p->uframe_sched = true;
+       p->external_id_pin_ctl = false;
+-      p->lpm = true;
+-      p->lpm_clock_gating = true;
+-      p->besl = true;
+-      p->hird_threshold_en = true;
+-      p->hird_threshold = 4;
+       p->ipg_isoc_en = false;
+       p->max_packet_count = hw->max_packet_count;
+       p->max_transfer_size = hw->max_transfer_size;
diff --git a/target/linux/generic/backport-5.4/210-arm64-sve-Disentangle-uapi-asm-ptrace.h-from-uapi-as.patch b/target/linux/generic/backport-5.4/210-arm64-sve-Disentangle-uapi-asm-ptrace.h-from-uapi-as.patch
new file mode 100644 (file)
index 0000000..7c574fd
--- /dev/null
@@ -0,0 +1,280 @@
+From 9966a05c7b80f075f2bc7e48dbb108d3f2927234 Mon Sep 17 00:00:00 2001
+From: Dave Martin <Dave.Martin@arm.com>
+Date: Fri, 4 Jan 2019 13:09:51 +0000
+Subject: [PATCH] arm64/sve: Disentangle <uapi/asm/ptrace.h> from
+ <uapi/asm/sigcontext.h>
+
+Currently, <uapi/asm/sigcontext.h> provides common definitions for
+describing SVE context structures that are also used by the ptrace
+definitions in <uapi/asm/ptrace.h>.
+
+For this reason, a #include of <asm/sigcontext.h> was added in
+ptrace.h, but it this turns out that this can interact badly with
+userspace code that tries to include ptrace.h on top of the libc
+headers (which may provide their own shadow definitions for
+sigcontext.h).
+
+To make the headers easier for userspace to consume, this patch
+bounces the common definitions into an __SVE_* namespace and moves
+them to a backend header <uapi/asm/sve_context.h> that can be
+included by the other headers as appropriate.  This should allow
+ptrace.h to be used alongside libc's sigcontext.h (if any) without
+ill effects.
+
+This should make the situation unambiguous: <asm/sigcontext.h> is
+the header to include for the sigframe-specific definitions, while
+<asm/ptrace.h> is the header to include for ptrace-specific
+definitions.
+
+To avoid conflicting with existing usage, <asm/sigcontext.h>
+remains the canonical way to get the common definitions for
+SVE_VQ_MIN, sve_vq_from_vl() etc., both in userspace and in the
+kernel: relying on these being defined as a side effect of
+including just <asm/ptrace.h> was never intended to be safe.
+
+Signed-off-by: Dave Martin <Dave.Martin@arm.com>
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+---
+ arch/arm64/include/uapi/asm/ptrace.h      | 39 ++++++++--------
+ arch/arm64/include/uapi/asm/sigcontext.h  | 56 +++++++++++------------
+ arch/arm64/include/uapi/asm/sve_context.h | 53 +++++++++++++++++++++
+ 3 files changed, 99 insertions(+), 49 deletions(-)
+ create mode 100644 arch/arm64/include/uapi/asm/sve_context.h
+
+--- a/arch/arm64/include/uapi/asm/ptrace.h
++++ b/arch/arm64/include/uapi/asm/ptrace.h
+@@ -23,7 +23,7 @@
+ #include <linux/types.h>
+ #include <asm/hwcap.h>
+-#include <asm/sigcontext.h>
++#include <asm/sve_context.h>
+ /*
+@@ -129,9 +129,9 @@ struct user_sve_header {
+  */
+ /* Offset from the start of struct user_sve_header to the register data */
+-#define SVE_PT_REGS_OFFSET                                    \
+-      ((sizeof(struct user_sve_header) + (SVE_VQ_BYTES - 1))  \
+-              / SVE_VQ_BYTES * SVE_VQ_BYTES)
++#define SVE_PT_REGS_OFFSET                                            \
++      ((sizeof(struct user_sve_header) + (__SVE_VQ_BYTES - 1))        \
++              / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
+ /*
+  * The register data content and layout depends on the value of the
+@@ -177,39 +177,36 @@ struct user_sve_header {
+  * Additional data might be appended in the future.
+  */
+-#define SVE_PT_SVE_ZREG_SIZE(vq)      SVE_SIG_ZREG_SIZE(vq)
+-#define SVE_PT_SVE_PREG_SIZE(vq)      SVE_SIG_PREG_SIZE(vq)
+-#define SVE_PT_SVE_FFR_SIZE(vq)               SVE_SIG_FFR_SIZE(vq)
++#define SVE_PT_SVE_ZREG_SIZE(vq)      __SVE_ZREG_SIZE(vq)
++#define SVE_PT_SVE_PREG_SIZE(vq)      __SVE_PREG_SIZE(vq)
++#define SVE_PT_SVE_FFR_SIZE(vq)               __SVE_FFR_SIZE(vq)
+ #define SVE_PT_SVE_FPSR_SIZE          sizeof(__u32)
+ #define SVE_PT_SVE_FPCR_SIZE          sizeof(__u32)
+-#define __SVE_SIG_TO_PT(offset) \
+-      ((offset) - SVE_SIG_REGS_OFFSET + SVE_PT_REGS_OFFSET)
+-
+ #define SVE_PT_SVE_OFFSET             SVE_PT_REGS_OFFSET
+ #define SVE_PT_SVE_ZREGS_OFFSET \
+-      __SVE_SIG_TO_PT(SVE_SIG_ZREGS_OFFSET)
++      (SVE_PT_REGS_OFFSET + __SVE_ZREGS_OFFSET)
+ #define SVE_PT_SVE_ZREG_OFFSET(vq, n) \
+-      __SVE_SIG_TO_PT(SVE_SIG_ZREG_OFFSET(vq, n))
++      (SVE_PT_REGS_OFFSET + __SVE_ZREG_OFFSET(vq, n))
+ #define SVE_PT_SVE_ZREGS_SIZE(vq) \
+-      (SVE_PT_SVE_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
++      (SVE_PT_SVE_ZREG_OFFSET(vq, __SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
+ #define SVE_PT_SVE_PREGS_OFFSET(vq) \
+-      __SVE_SIG_TO_PT(SVE_SIG_PREGS_OFFSET(vq))
++      (SVE_PT_REGS_OFFSET + __SVE_PREGS_OFFSET(vq))
+ #define SVE_PT_SVE_PREG_OFFSET(vq, n) \
+-      __SVE_SIG_TO_PT(SVE_SIG_PREG_OFFSET(vq, n))
++      (SVE_PT_REGS_OFFSET + __SVE_PREG_OFFSET(vq, n))
+ #define SVE_PT_SVE_PREGS_SIZE(vq) \
+-      (SVE_PT_SVE_PREG_OFFSET(vq, SVE_NUM_PREGS) - \
++      (SVE_PT_SVE_PREG_OFFSET(vq, __SVE_NUM_PREGS) - \
+               SVE_PT_SVE_PREGS_OFFSET(vq))
+ #define SVE_PT_SVE_FFR_OFFSET(vq) \
+-      __SVE_SIG_TO_PT(SVE_SIG_FFR_OFFSET(vq))
++      (SVE_PT_REGS_OFFSET + __SVE_FFR_OFFSET(vq))
+ #define SVE_PT_SVE_FPSR_OFFSET(vq)                            \
+       ((SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq) + \
+-                      (SVE_VQ_BYTES - 1))                     \
+-              / SVE_VQ_BYTES * SVE_VQ_BYTES)
++                      (__SVE_VQ_BYTES - 1))                   \
++              / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
+ #define SVE_PT_SVE_FPCR_OFFSET(vq) \
+       (SVE_PT_SVE_FPSR_OFFSET(vq) + SVE_PT_SVE_FPSR_SIZE)
+@@ -220,8 +217,8 @@ struct user_sve_header {
+ #define SVE_PT_SVE_SIZE(vq, flags)                                    \
+       ((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE             \
+-                      - SVE_PT_SVE_OFFSET + (SVE_VQ_BYTES - 1))       \
+-              / SVE_VQ_BYTES * SVE_VQ_BYTES)
++                      - SVE_PT_SVE_OFFSET + (__SVE_VQ_BYTES - 1))     \
++              / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
+ #define SVE_PT_SIZE(vq, flags)                                                \
+        (((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ?             \
+--- a/arch/arm64/include/uapi/asm/sigcontext.h
++++ b/arch/arm64/include/uapi/asm/sigcontext.h
+@@ -130,6 +130,8 @@ struct sve_context {
+ #endif /* !__ASSEMBLY__ */
++#include <asm/sve_context.h>
++
+ /*
+  * The SVE architecture leaves space for future expansion of the
+  * vector length beyond its initial architectural limit of 2048 bits
+@@ -138,21 +140,20 @@ struct sve_context {
+  * See linux/Documentation/arm64/sve.txt for a description of the VL/VQ
+  * terminology.
+  */
+-#define SVE_VQ_BYTES          16      /* number of bytes per quadword */
++#define SVE_VQ_BYTES          __SVE_VQ_BYTES  /* bytes per quadword */
+-#define SVE_VQ_MIN            1
+-#define SVE_VQ_MAX            512
++#define SVE_VQ_MIN            __SVE_VQ_MIN
++#define SVE_VQ_MAX            __SVE_VQ_MAX
+-#define SVE_VL_MIN            (SVE_VQ_MIN * SVE_VQ_BYTES)
+-#define SVE_VL_MAX            (SVE_VQ_MAX * SVE_VQ_BYTES)
++#define SVE_VL_MIN            __SVE_VL_MIN
++#define SVE_VL_MAX            __SVE_VL_MAX
+-#define SVE_NUM_ZREGS         32
+-#define SVE_NUM_PREGS         16
++#define SVE_NUM_ZREGS         __SVE_NUM_ZREGS
++#define SVE_NUM_PREGS         __SVE_NUM_PREGS
+-#define sve_vl_valid(vl) \
+-      ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX)
+-#define sve_vq_from_vl(vl)    ((vl) / SVE_VQ_BYTES)
+-#define sve_vl_from_vq(vq)    ((vq) * SVE_VQ_BYTES)
++#define sve_vl_valid(vl)      __sve_vl_valid(vl)
++#define sve_vq_from_vl(vl)    __sve_vq_from_vl(vl)
++#define sve_vl_from_vq(vq)    __sve_vl_from_vq(vq)
+ /*
+  * If the SVE registers are currently live for the thread at signal delivery,
+@@ -205,34 +206,33 @@ struct sve_context {
+  * Additional data might be appended in the future.
+  */
+-#define SVE_SIG_ZREG_SIZE(vq) ((__u32)(vq) * SVE_VQ_BYTES)
+-#define SVE_SIG_PREG_SIZE(vq) ((__u32)(vq) * (SVE_VQ_BYTES / 8))
+-#define SVE_SIG_FFR_SIZE(vq)  SVE_SIG_PREG_SIZE(vq)
++#define SVE_SIG_ZREG_SIZE(vq) __SVE_ZREG_SIZE(vq)
++#define SVE_SIG_PREG_SIZE(vq) __SVE_PREG_SIZE(vq)
++#define SVE_SIG_FFR_SIZE(vq)  __SVE_FFR_SIZE(vq)
+ #define SVE_SIG_REGS_OFFSET                                   \
+-      ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1))      \
+-              / SVE_VQ_BYTES * SVE_VQ_BYTES)
++      ((sizeof(struct sve_context) + (__SVE_VQ_BYTES - 1))    \
++              / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
+-#define SVE_SIG_ZREGS_OFFSET  SVE_SIG_REGS_OFFSET
++#define SVE_SIG_ZREGS_OFFSET \
++              (SVE_SIG_REGS_OFFSET + __SVE_ZREGS_OFFSET)
+ #define SVE_SIG_ZREG_OFFSET(vq, n) \
+-      (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n))
+-#define SVE_SIG_ZREGS_SIZE(vq) \
+-      (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET)
++              (SVE_SIG_REGS_OFFSET + __SVE_ZREG_OFFSET(vq, n))
++#define SVE_SIG_ZREGS_SIZE(vq) __SVE_ZREGS_SIZE(vq)
+ #define SVE_SIG_PREGS_OFFSET(vq) \
+-      (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq))
++              (SVE_SIG_REGS_OFFSET + __SVE_PREGS_OFFSET(vq))
+ #define SVE_SIG_PREG_OFFSET(vq, n) \
+-      (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n))
+-#define SVE_SIG_PREGS_SIZE(vq) \
+-      (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq))
++              (SVE_SIG_REGS_OFFSET + __SVE_PREG_OFFSET(vq, n))
++#define SVE_SIG_PREGS_SIZE(vq) __SVE_PREGS_SIZE(vq)
+ #define SVE_SIG_FFR_OFFSET(vq) \
+-      (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq))
++              (SVE_SIG_REGS_OFFSET + __SVE_FFR_OFFSET(vq))
+ #define SVE_SIG_REGS_SIZE(vq) \
+-      (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET)
+-
+-#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq))
++              (__SVE_FFR_OFFSET(vq) + __SVE_FFR_SIZE(vq))
++#define SVE_SIG_CONTEXT_SIZE(vq) \
++              (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq))
+ #endif /* _UAPI__ASM_SIGCONTEXT_H */
+--- /dev/null
++++ b/arch/arm64/include/uapi/asm/sve_context.h
+@@ -0,0 +1,53 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++/* Copyright (C) 2017-2018 ARM Limited */
++
++/*
++ * For use by other UAPI headers only.
++ * Do not make direct use of header or its definitions.
++ */
++
++#ifndef _UAPI__ASM_SVE_CONTEXT_H
++#define _UAPI__ASM_SVE_CONTEXT_H
++
++#include <linux/types.h>
++
++#define __SVE_VQ_BYTES                16      /* number of bytes per quadword */
++
++#define __SVE_VQ_MIN          1
++#define __SVE_VQ_MAX          512
++
++#define __SVE_VL_MIN          (__SVE_VQ_MIN * __SVE_VQ_BYTES)
++#define __SVE_VL_MAX          (__SVE_VQ_MAX * __SVE_VQ_BYTES)
++
++#define __SVE_NUM_ZREGS               32
++#define __SVE_NUM_PREGS               16
++
++#define __sve_vl_valid(vl)                    \
++      ((vl) % __SVE_VQ_BYTES == 0 &&          \
++       (vl) >= __SVE_VL_MIN &&                \
++       (vl) <= __SVE_VL_MAX)
++
++#define __sve_vq_from_vl(vl)  ((vl) / __SVE_VQ_BYTES)
++#define __sve_vl_from_vq(vq)  ((vq) * __SVE_VQ_BYTES)
++
++#define __SVE_ZREG_SIZE(vq)   ((__u32)(vq) * __SVE_VQ_BYTES)
++#define __SVE_PREG_SIZE(vq)   ((__u32)(vq) * (__SVE_VQ_BYTES / 8))
++#define __SVE_FFR_SIZE(vq)    __SVE_PREG_SIZE(vq)
++
++#define __SVE_ZREGS_OFFSET    0
++#define __SVE_ZREG_OFFSET(vq, n) \
++      (__SVE_ZREGS_OFFSET + __SVE_ZREG_SIZE(vq) * (n))
++#define __SVE_ZREGS_SIZE(vq) \
++      (__SVE_ZREG_OFFSET(vq, __SVE_NUM_ZREGS) - __SVE_ZREGS_OFFSET)
++
++#define __SVE_PREGS_OFFSET(vq) \
++      (__SVE_ZREGS_OFFSET + __SVE_ZREGS_SIZE(vq))
++#define __SVE_PREG_OFFSET(vq, n) \
++      (__SVE_PREGS_OFFSET(vq) + __SVE_PREG_SIZE(vq) * (n))
++#define __SVE_PREGS_SIZE(vq) \
++      (__SVE_PREG_OFFSET(vq, __SVE_NUM_PREGS) - __SVE_PREGS_OFFSET(vq))
++
++#define __SVE_FFR_OFFSET(vq) \
++      (__SVE_PREGS_OFFSET(vq) + __SVE_PREGS_SIZE(vq))
++
++#endif /* ! _UAPI__ASM_SVE_CONTEXT_H */
diff --git a/target/linux/generic/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch b/target/linux/generic/backport-5.4/343-netfilter-nft_flow_offload-handle-netdevice-events-f.patch
new file mode 100644 (file)
index 0000000..577f2d3
--- /dev/null
@@ -0,0 +1,99 @@
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 25 Jan 2018 12:58:55 +0100
+Subject: [PATCH] netfilter: nft_flow_offload: handle netdevice events from
+ nf_flow_table
+
+Move the code that deals with device events to the core.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+---
+
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -535,5 +535,35 @@ void nf_flow_table_free(struct nf_flowta
+ }
+ EXPORT_SYMBOL_GPL(nf_flow_table_free);
++static int nf_flow_table_netdev_event(struct notifier_block *this,
++                                    unsigned long event, void *ptr)
++{
++      struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++
++      if (event != NETDEV_DOWN)
++              return NOTIFY_DONE;
++
++      nf_flow_table_cleanup(dev_net(dev), dev);
++
++      return NOTIFY_DONE;
++}
++
++static struct notifier_block flow_offload_netdev_notifier = {
++      .notifier_call  = nf_flow_table_netdev_event,
++};
++
++static int __init nf_flow_table_module_init(void)
++{
++      return register_netdevice_notifier(&flow_offload_netdev_notifier);
++}
++
++static void __exit nf_flow_table_module_exit(void)
++{
++      unregister_netdevice_notifier(&flow_offload_netdev_notifier);
++}
++
++module_init(nf_flow_table_module_init);
++module_exit(nf_flow_table_module_exit);
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -216,47 +216,14 @@ static struct nft_expr_type nft_flow_off
+       .owner          = THIS_MODULE,
+ };
+-static int flow_offload_netdev_event(struct notifier_block *this,
+-                                   unsigned long event, void *ptr)
+-{
+-      struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+-
+-      if (event != NETDEV_DOWN)
+-              return NOTIFY_DONE;
+-
+-      nf_flow_table_cleanup(dev_net(dev), dev);
+-
+-      return NOTIFY_DONE;
+-}
+-
+-static struct notifier_block flow_offload_netdev_notifier = {
+-      .notifier_call  = flow_offload_netdev_event,
+-};
+-
+ static int __init nft_flow_offload_module_init(void)
+ {
+-      int err;
+-
+-      err = register_netdevice_notifier(&flow_offload_netdev_notifier);
+-      if (err)
+-              goto err;
+-
+-      err = nft_register_expr(&nft_flow_offload_type);
+-      if (err < 0)
+-              goto register_expr;
+-
+-      return 0;
+-
+-register_expr:
+-      unregister_netdevice_notifier(&flow_offload_netdev_notifier);
+-err:
+-      return err;
++      return nft_register_expr(&nft_flow_offload_type);
+ }
+ static void __exit nft_flow_offload_module_exit(void)
+ {
+       nft_unregister_expr(&nft_flow_offload_type);
+-      unregister_netdevice_notifier(&flow_offload_netdev_notifier);
+ }
+ module_init(nft_flow_offload_module_init);
diff --git a/target/linux/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch b/target/linux/generic/backport-5.4/370-netfilter-nf_flow_table-fix-offloaded-connection-tim.patch
new file mode 100644 (file)
index 0000000..7c10f6f
--- /dev/null
@@ -0,0 +1,112 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 13 Jun 2018 12:33:39 +0200
+Subject: [PATCH] netfilter: nf_flow_table: fix offloaded connection timeout
+ corner case
+
+The full teardown of offloaded flows is deferred to a gc work item,
+however processing of packets by netfilter needs to happen immediately
+after a teardown is requested, because the conntrack state needs to be
+fixed up.
+
+Since the IPS_OFFLOAD_BIT is still kept until the teardown is complete,
+the netfilter conntrack gc can accidentally bump the timeout of a
+connection where offload was just stopped, causing a conntrack entry
+leak.
+
+Fix this by moving the conntrack timeout bumping from conntrack core to
+the nf_flow_offload and add a check to prevent bogus timeout bumps.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -1178,18 +1178,6 @@ static bool gc_worker_can_early_drop(con
+       return false;
+ }
+-#define       DAY     (86400 * HZ)
+-
+-/* Set an arbitrary timeout large enough not to ever expire, this save
+- * us a check for the IPS_OFFLOAD_BIT from the packet path via
+- * nf_ct_is_expired().
+- */
+-static void nf_ct_offload_timeout(struct nf_conn *ct)
+-{
+-      if (nf_ct_expires(ct) < DAY / 2)
+-              ct->timeout = nfct_time_stamp + DAY;
+-}
+-
+ static void gc_worker(struct work_struct *work)
+ {
+       unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u);
+@@ -1226,10 +1214,8 @@ static void gc_worker(struct work_struct
+                       tmp = nf_ct_tuplehash_to_ctrack(h);
+                       scanned++;
+-                      if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
+-                              nf_ct_offload_timeout(tmp);
++                      if (test_bit(IPS_OFFLOAD_BIT, &tmp->status))
+                               continue;
+-                      }
+                       if (nf_ct_is_expired(tmp)) {
+                               nf_ct_gc_expired(tmp);
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -183,10 +183,29 @@ static const struct rhashtable_params nf
+       .automatic_shrinking    = true,
+ };
++#define        DAY     (86400 * HZ)
++
++/* Set an arbitrary timeout large enough not to ever expire, this save
++ * us a check for the IPS_OFFLOAD_BIT from the packet path via
++ * nf_ct_is_expired().
++ */
++static void nf_ct_offload_timeout(struct flow_offload *flow)
++{
++      struct flow_offload_entry *entry;
++      struct nf_conn *ct;
++
++      entry = container_of(flow, struct flow_offload_entry, flow);
++      ct = entry->ct;
++
++      if (nf_ct_expires(ct) < DAY / 2)
++              ct->timeout = nfct_time_stamp + DAY;
++}
++
+ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
+ {
+       int err;
++      nf_ct_offload_timeout(flow);
+       flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
+       err = rhashtable_insert_fast(&flow_table->rhashtable,
+@@ -317,6 +336,8 @@ static int nf_flow_offload_gc_step(struc
+       rhashtable_walk_start(&hti);
+       while ((tuplehash = rhashtable_walk_next(&hti))) {
++              bool teardown;
++
+               if (IS_ERR(tuplehash)) {
+                       err = PTR_ERR(tuplehash);
+                       if (err != -EAGAIN)
+@@ -329,9 +350,13 @@ static int nf_flow_offload_gc_step(struc
+               flow = container_of(tuplehash, struct flow_offload, tuplehash[0]);
+-              if (nf_flow_has_expired(flow) ||
+-                  (flow->flags & (FLOW_OFFLOAD_DYING |
+-                                  FLOW_OFFLOAD_TEARDOWN)))
++              teardown = flow->flags & (FLOW_OFFLOAD_DYING |
++                                        FLOW_OFFLOAD_TEARDOWN);
++
++              if (!teardown)
++                      nf_ct_offload_timeout(flow);
++
++              if (nf_flow_has_expired(flow) || teardown)
+                       flow_offload_del(flow_table, flow);
+       }
+ out:
diff --git a/target/linux/generic/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch b/target/linux/generic/backport-5.4/371-netfilter-nf_flow_table-fix-up-ct-state-of-flows-aft.patch
new file mode 100644 (file)
index 0000000..2e25066
--- /dev/null
@@ -0,0 +1,24 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 14 Jun 2018 11:20:09 +0200
+Subject: [PATCH] netfilter: nf_flow_table: fix up ct state of flows after
+ timeout
+
+If a connection simply times out instead of being torn down, it is left
+active with a long timeout. Fix this by calling flow_offload_fixup_ct_state
+here as well.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/netfilter/nf_flow_table_core.c
++++ b/net/netfilter/nf_flow_table_core.c
+@@ -243,6 +243,9 @@ static void flow_offload_del(struct nf_f
+       e = container_of(flow, struct flow_offload_entry, flow);
+       clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
++      if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
++              flow_offload_fixup_ct_state(e->ct);
++
+       flow_offload_free(flow);
+ }
diff --git a/target/linux/generic/backport-5.4/380-v5.3-net-sched-Introduce-act_ctinfo-action.patch b/target/linux/generic/backport-5.4/380-v5.3-net-sched-Introduce-act_ctinfo-action.patch
new file mode 100644 (file)
index 0000000..a680402
--- /dev/null
@@ -0,0 +1,670 @@
+From d129a72f465dab2d9fc8f1580c38600a8b808327 Mon Sep 17 00:00:00 2001
+From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Date: Wed, 13 Mar 2019 20:54:49 +0000
+Subject: [PATCH] net: sched: Backport Introduce act_ctinfo action
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+ctinfo is a new tc filter action module.  It is designed to restore
+information contained in firewall conntrack marks to other packet fields
+and is typically used on packet ingress paths.  At present it has two
+independent sub-functions or operating modes, DSCP restoration mode &
+skb mark restoration mode.
+
+The DSCP restore mode:
+
+This mode copies DSCP values that have been placed in the firewall
+conntrack mark back into the IPv4/v6 diffserv fields of relevant
+packets.
+
+The DSCP restoration is intended for use and has been found useful for
+restoring ingress classifications based on egress classifications across
+links that bleach or otherwise change DSCP, typically home ISP Internet
+links.  Restoring DSCP on ingress on the WAN link allows qdiscs such as
+but by no means limited to CAKE to shape inbound packets according to
+policies that are easier to set & mark on egress.
+
+Ingress classification is traditionally a challenging task since
+iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT
+lookups, hence are unable to see internal IPv4 addresses as used on the
+typical home masquerading gateway.  Thus marking the connection in some
+manner on egress for later restoration of classification on ingress is
+easier to implement.
+
+Parameters related to DSCP restore mode:
+
+dscpmask - a 32 bit mask of 6 contiguous bits and indicate bits of the
+conntrack mark field contain the DSCP value to be restored.
+
+statemask - a 32 bit mask of (usually) 1 bit length, outside the area
+specified by dscpmask.  This represents a conditional operation flag
+whereby the DSCP is only restored if the flag is set.  This is useful to
+implement a 'one shot' iptables based classification where the
+'complicated' iptables rules are only run once to classify the
+connection on initial (egress) packet and subsequent packets are all
+marked/restored with the same DSCP.  A mask of zero disables the
+conditional behaviour ie. the conntrack mark DSCP bits are always
+restored to the ip diffserv field (assuming the conntrack entry is found
+& the skb is an ipv4/ipv6 type)
+
+e.g. dscpmask 0xfc000000 statemask 0x01000000
+
+|----0xFC----conntrack mark----000000---|
+| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
+| DSCP       | unused | flag  |unused   |
+|-----------------------0x01---000000---|
+      |                   |
+      |                   |
+      ---|             Conditional flag
+         v             only restore if set
+|-ip diffserv-|
+| 6 bits      |
+|-------------|
+
+The skb mark restore mode (cpmark):
+
+This mode copies the firewall conntrack mark to the skb's mark field.
+It is completely the functional equivalent of the existing act_connmark
+action with the additional feature of being able to apply a mask to the
+restored value.
+
+Parameters related to skb mark restore mode:
+
+mask - a 32 bit mask applied to the firewall conntrack mark to mask out
+bits unwanted for restoration.  This can be useful where the conntrack
+mark is being used for different purposes by different applications.  If
+not specified and by default the whole mark field is copied (i.e.
+default mask of 0xffffffff)
+
+e.g. mask 0x00ffffff to mask out the top 8 bits being used by the
+aforementioned DSCP restore mode.
+
+|----0x00----conntrack mark----ffffff---|
+| Bits 31-24 |                          |
+| DSCP & flag|      some value here     |
+|---------------------------------------|
+                       |
+                       |
+                       v
+|------------skb mark-------------------|
+|            |                          |
+|  zeroed    |                          |
+|---------------------------------------|
+
+Overall parameters:
+
+zone - conntrack zone
+
+control - action related control (reclassify | pipe | drop | continue |
+ok | goto chain <CHAIN_INDEX>)
+
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Backport
+Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
+---
+ include/net/tc_act/tc_ctinfo.h            |  33 ++
+ include/uapi/linux/pkt_cls.h              |   3 +-
+ include/uapi/linux/tc_act/tc_ctinfo.h     |  29 ++
+ net/sched/Kconfig                         |  17 +
+ net/sched/Makefile                        |   1 +
+ net/sched/act_ctinfo.c                    | 420 ++++++++++++++++++++++
+ tools/testing/selftests/tc-testing/config |   1 +
+ 7 files changed, 503 insertions(+), 1 deletion(-)
+ create mode 100644 include/net/tc_act/tc_ctinfo.h
+ create mode 100644 include/uapi/linux/tc_act/tc_ctinfo.h
+ create mode 100644 net/sched/act_ctinfo.c
+
+--- /dev/null
++++ b/include/net/tc_act/tc_ctinfo.h
+@@ -0,0 +1,33 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++#ifndef __NET_TC_CTINFO_H
++#define __NET_TC_CTINFO_H
++
++#include <net/act_api.h>
++
++struct tcf_ctinfo_params {
++      struct rcu_head rcu;
++      struct net *net;
++      u32 dscpmask;
++      u32 dscpstatemask;
++      u32 cpmarkmask;
++      u16 zone;
++      u8 mode;
++      u8 dscpmaskshift;
++};
++
++struct tcf_ctinfo {
++      struct tc_action common;
++      struct tcf_ctinfo_params __rcu *params;
++      u64 stats_dscp_set;
++      u64 stats_dscp_error;
++      u64 stats_cpmark_set;
++};
++
++enum {
++      CTINFO_MODE_DSCP        = BIT(0),
++      CTINFO_MODE_CPMARK      = BIT(1)
++};
++
++#define to_ctinfo(a) ((struct tcf_ctinfo *)a)
++
++#endif /* __NET_TC_CTINFO_H */
+--- a/include/uapi/linux/pkt_cls.h
++++ b/include/uapi/linux/pkt_cls.h
+@@ -68,7 +68,8 @@ enum {
+       TCA_ID_UNSPEC=0,
+       TCA_ID_POLICE=1,
+       /* other actions go here */
+-      __TCA_ID_MAX=255
++      TCA_ID_CTINFO,
++      __TCA_ID_MAX = 255
+ };
+ #define TCA_ID_MAX __TCA_ID_MAX
+--- /dev/null
++++ b/include/uapi/linux/tc_act/tc_ctinfo.h
+@@ -0,0 +1,29 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef __UAPI_TC_CTINFO_H
++#define __UAPI_TC_CTINFO_H
++
++#include <linux/types.h>
++#include <linux/pkt_cls.h>
++
++struct tc_ctinfo {
++      tc_gen;
++};
++
++enum {
++      TCA_CTINFO_UNSPEC,
++      TCA_CTINFO_PAD,
++      TCA_CTINFO_TM,
++      TCA_CTINFO_ACT,
++      TCA_CTINFO_ZONE,
++      TCA_CTINFO_PARMS_DSCP_MASK,
++      TCA_CTINFO_PARMS_DSCP_STATEMASK,
++      TCA_CTINFO_PARMS_CPMARK_MASK,
++      TCA_CTINFO_STATS_DSCP_SET,
++      TCA_CTINFO_STATS_DSCP_ERROR,
++      TCA_CTINFO_STATS_CPMARK_SET,
++      __TCA_CTINFO_MAX
++};
++
++#define TCA_CTINFO_MAX (__TCA_CTINFO_MAX - 1)
++
++#endif
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -866,6 +866,23 @@ config NET_ACT_CONNMARK
+         To compile this code as a module, choose M here: the
+         module will be called act_connmark.
++config NET_ACT_CTINFO
++        tristate "Netfilter Connection Mark Actions"
++        depends on NET_CLS_ACT && NETFILTER && IP_NF_IPTABLES
++        depends on NF_CONNTRACK && NF_CONNTRACK_MARK
++        help
++        Say Y here to allow transfer of a connmark stored information.
++        Current actions transfer connmark stored DSCP into
++        ipv4/v6 diffserv and/or to transfer connmark to packet
++        mark.  Both are useful for restoring egress based marks
++        back onto ingress connections for qdisc priority mapping
++        purposes.
++
++        If unsure, say N.
++
++        To compile this code as a module, choose M here: the
++        module will be called act_ctinfo.
++
+ config NET_ACT_SKBMOD
+         tristate "skb data modification action"
+         depends on NET_CLS_ACT
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -21,6 +21,7 @@ obj-$(CONFIG_NET_ACT_CSUM)   += act_csum.o
+ obj-$(CONFIG_NET_ACT_VLAN)    += act_vlan.o
+ obj-$(CONFIG_NET_ACT_BPF)     += act_bpf.o
+ obj-$(CONFIG_NET_ACT_CONNMARK)        += act_connmark.o
++obj-$(CONFIG_NET_ACT_CTINFO)  += act_ctinfo.o
+ obj-$(CONFIG_NET_ACT_SKBMOD)  += act_skbmod.o
+ obj-$(CONFIG_NET_ACT_IFE)     += act_ife.o
+ obj-$(CONFIG_NET_IFE_SKBMARK) += act_meta_mark.o
+--- /dev/null
++++ b/net/sched/act_ctinfo.c
+@@ -0,0 +1,420 @@
++// SPDX-License-Identifier: GPL-2.0+
++/* net/sched/act_ctinfo.c  netfilter ctinfo connmark actions
++ *
++ * Copyright (c) 2019 Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++#include <net/pkt_cls.h>
++#include <uapi/linux/tc_act/tc_ctinfo.h>
++#include <net/tc_act/tc_ctinfo.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++#include <net/netfilter/nf_conntrack_ecache.h>
++#include <net/netfilter/nf_conntrack_zones.h>
++
++static struct tc_action_ops act_ctinfo_ops;
++static unsigned int ctinfo_net_id;
++
++static void tcf_ctinfo_dscp_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
++                              struct tcf_ctinfo_params *cp,
++                              struct sk_buff *skb, int wlen, int proto)
++{
++      u8 dscp, newdscp;
++
++      newdscp = (((ct->mark & cp->dscpmask) >> cp->dscpmaskshift) << 2) &
++                   ~INET_ECN_MASK;
++
++      switch (proto) {
++      case NFPROTO_IPV4:
++              dscp = ipv4_get_dsfield(ip_hdr(skb)) & ~INET_ECN_MASK;
++              if (dscp != newdscp) {
++                      if (likely(!skb_try_make_writable(skb, wlen))) {
++                              ipv4_change_dsfield(ip_hdr(skb),
++                                                  INET_ECN_MASK,
++                                                  newdscp);
++                              ca->stats_dscp_set++;
++                      } else {
++                              ca->stats_dscp_error++;
++                      }
++              }
++              break;
++      case NFPROTO_IPV6:
++              dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & ~INET_ECN_MASK;
++              if (dscp != newdscp) {
++                      if (likely(!skb_try_make_writable(skb, wlen))) {
++                              ipv6_change_dsfield(ipv6_hdr(skb),
++                                                  INET_ECN_MASK,
++                                                  newdscp);
++                              ca->stats_dscp_set++;
++                      } else {
++                              ca->stats_dscp_error++;
++                      }
++              }
++              break;
++      default:
++              break;
++      }
++}
++
++static void tcf_ctinfo_cpmark_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
++                                struct tcf_ctinfo_params *cp,
++                                struct sk_buff *skb)
++{
++      ca->stats_cpmark_set++;
++      skb->mark = ct->mark & cp->cpmarkmask;
++}
++
++static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a,
++                        struct tcf_result *res)
++{
++      const struct nf_conntrack_tuple_hash *thash = NULL;
++      struct tcf_ctinfo *ca = to_ctinfo(a);
++      struct nf_conntrack_tuple tuple;
++      struct nf_conntrack_zone zone;
++      enum ip_conntrack_info ctinfo;
++      struct tcf_ctinfo_params *cp;
++      struct nf_conn *ct;
++      int proto, wlen;
++      int action;
++
++      cp = rcu_dereference_bh(ca->params);
++
++      tcf_lastuse_update(&ca->tcf_tm);
++      bstats_update(&ca->tcf_bstats, skb);
++      action = READ_ONCE(ca->tcf_action);
++
++      wlen = skb_network_offset(skb);
++      if (tc_skb_protocol(skb) == htons(ETH_P_IP)) {
++              wlen += sizeof(struct iphdr);
++              if (!pskb_may_pull(skb, wlen))
++                      goto out;
++
++              proto = NFPROTO_IPV4;
++      } else if (tc_skb_protocol(skb) == htons(ETH_P_IPV6)) {
++              wlen += sizeof(struct ipv6hdr);
++              if (!pskb_may_pull(skb, wlen))
++                      goto out;
++
++              proto = NFPROTO_IPV6;
++      } else {
++              goto out;
++      }
++
++      ct = nf_ct_get(skb, &ctinfo);
++      if (!ct) { /* look harder, usually ingress */
++              if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
++                                     proto, cp->net, &tuple))
++                      goto out;
++              zone.id = cp->zone;
++              zone.dir = NF_CT_DEFAULT_ZONE_DIR;
++
++              thash = nf_conntrack_find_get(cp->net, &zone, &tuple);
++              if (!thash)
++                      goto out;
++
++              ct = nf_ct_tuplehash_to_ctrack(thash);
++      }
++
++      if (cp->mode & CTINFO_MODE_DSCP)
++              if (!cp->dscpstatemask || (ct->mark & cp->dscpstatemask))
++                      tcf_ctinfo_dscp_set(ct, ca, cp, skb, wlen, proto);
++
++      if (cp->mode & CTINFO_MODE_CPMARK)
++              tcf_ctinfo_cpmark_set(ct, ca, cp, skb);
++
++      if (thash)
++              nf_ct_put(ct);
++out:
++      return action;
++}
++
++static const struct nla_policy ctinfo_policy[TCA_CTINFO_MAX + 1] = {
++      [TCA_CTINFO_ACT]                  = { .len = sizeof(struct
++                                                          tc_ctinfo) },
++      [TCA_CTINFO_ZONE]                 = { .type = NLA_U16 },
++      [TCA_CTINFO_PARMS_DSCP_MASK]      = { .type = NLA_U32 },
++      [TCA_CTINFO_PARMS_DSCP_STATEMASK] = { .type = NLA_U32 },
++      [TCA_CTINFO_PARMS_CPMARK_MASK]    = { .type = NLA_U32 },
++};
++
++static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
++                         struct nlattr *est, struct tc_action **a,
++                         int ovr, int bind, bool rtnl_held,
++                         struct netlink_ext_ack *extack)
++{
++      struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
++      u32 dscpmask = 0, dscpstatemask, index;
++      struct nlattr *tb[TCA_CTINFO_MAX + 1];
++      struct tcf_ctinfo_params *cp_new;
++/*    struct tcf_chain *goto_ch = NULL; */
++      struct tc_ctinfo *actparm;
++      struct tcf_ctinfo *ci;
++      u8 dscpmaskshift;
++      int ret = 0, err;
++
++      if (!nla) {
++              NL_SET_ERR_MSG_MOD(extack, "ctinfo requires attributes to be passed");
++              return -EINVAL;
++      }
++
++      err = nla_parse_nested(tb, TCA_CTINFO_MAX, nla, ctinfo_policy, extack);
++      if (err < 0)
++              return err;
++
++      if (!tb[TCA_CTINFO_ACT]) {
++              NL_SET_ERR_MSG_MOD(extack,
++                                 "Missing required TCA_CTINFO_ACT attribute");
++              return -EINVAL;
++      }
++      actparm = nla_data(tb[TCA_CTINFO_ACT]);
++
++      /* do some basic validation here before dynamically allocating things */
++      /* that we would otherwise have to clean up.                          */
++      if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) {
++              dscpmask = nla_get_u32(tb[TCA_CTINFO_PARMS_DSCP_MASK]);
++              /* need contiguous 6 bit mask */
++              dscpmaskshift = dscpmask ? __ffs(dscpmask) : 0;
++              if ((~0 & (dscpmask >> dscpmaskshift)) != 0x3f) {
++                      NL_SET_ERR_MSG_ATTR(extack,
++                                          tb[TCA_CTINFO_PARMS_DSCP_MASK],
++                                          "dscp mask must be 6 contiguous bits");
++                      return -EINVAL;
++              }
++              dscpstatemask = tb[TCA_CTINFO_PARMS_DSCP_STATEMASK] ?
++                      nla_get_u32(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) : 0;
++              /* mask & statemask must not overlap */
++              if (dscpmask & dscpstatemask) {
++                      NL_SET_ERR_MSG_ATTR(extack,
++                                          tb[TCA_CTINFO_PARMS_DSCP_STATEMASK],
++                                          "dscp statemask must not overlap dscp mask");
++                      return -EINVAL;
++              }
++      }
++
++      /* done the validation:now to the actual action allocation */
++      index = actparm->index;
++      err = tcf_idr_check_alloc(tn, &index, a, bind);
++      if (!err) {
++              ret = tcf_idr_create(tn, index, est, a,
++                                   &act_ctinfo_ops, bind, false);
++              if (ret) {
++                      tcf_idr_cleanup(tn, index);
++                      return ret;
++              }
++              ret = ACT_P_CREATED;
++      } else if (err > 0) {
++              if (bind) /* don't override defaults */
++                      return 0;
++              if (!ovr) {
++                      tcf_idr_release(*a, bind);
++                      return -EEXIST;
++              }
++      } else {
++              return err;
++      }
++
++/*    err = tcf_action_check_ctrlact(actparm->action, tp, &goto_ch, extack);
++      if (err < 0)
++              goto release_idr;
++              */
++
++      ci = to_ctinfo(*a);
++
++      cp_new = kzalloc(sizeof(*cp_new), GFP_KERNEL);
++      if (unlikely(!cp_new)) {
++              err = -ENOMEM;
++              goto put_chain;
++      }
++
++      cp_new->net = net;
++      cp_new->zone = tb[TCA_CTINFO_ZONE] ?
++                      nla_get_u16(tb[TCA_CTINFO_ZONE]) : 0;
++      if (dscpmask) {
++              cp_new->dscpmask = dscpmask;
++              cp_new->dscpmaskshift = dscpmaskshift;
++              cp_new->dscpstatemask = dscpstatemask;
++              cp_new->mode |= CTINFO_MODE_DSCP;
++      }
++
++      if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) {
++              cp_new->cpmarkmask =
++                              nla_get_u32(tb[TCA_CTINFO_PARMS_CPMARK_MASK]);
++              cp_new->mode |= CTINFO_MODE_CPMARK;
++      }
++
++      spin_lock_bh(&ci->tcf_lock);
++/*    goto_ch = tcf_action_set_ctrlact(*a, actparm->action, goto_ch); */
++      ci->tcf_action = actparm->action;
++      rcu_swap_protected(ci->params, cp_new,
++                         lockdep_is_held(&ci->tcf_lock));
++      spin_unlock_bh(&ci->tcf_lock);
++
++/*    if (goto_ch)
++              tcf_chain_put_by_act(goto_ch); */
++      if (cp_new)
++              kfree_rcu(cp_new, rcu);
++
++      if (ret == ACT_P_CREATED)
++              tcf_idr_insert(tn, *a);
++
++      return ret;
++
++put_chain:
++/*    if (goto_ch)
++              tcf_chain_put_by_act(goto_ch);
++release_idr: */
++      tcf_idr_release(*a, bind);
++      return err;
++}
++
++static int tcf_ctinfo_dump(struct sk_buff *skb, struct tc_action *a,
++                         int bind, int ref)
++{
++      struct tcf_ctinfo *ci = to_ctinfo(a);
++      struct tc_ctinfo opt = {
++              .index   = ci->tcf_index,
++              .refcnt  = refcount_read(&ci->tcf_refcnt) - ref,
++              .bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
++      };
++      unsigned char *b = skb_tail_pointer(skb);
++      struct tcf_ctinfo_params *cp;
++      struct tcf_t t;
++
++      spin_lock_bh(&ci->tcf_lock);
++      cp = rcu_dereference_protected(ci->params,
++                                     lockdep_is_held(&ci->tcf_lock));
++
++      tcf_tm_dump(&t, &ci->tcf_tm);
++      if (nla_put_64bit(skb, TCA_CTINFO_TM, sizeof(t), &t, TCA_CTINFO_PAD))
++              goto nla_put_failure;
++
++      opt.action = ci->tcf_action;
++      if (nla_put(skb, TCA_CTINFO_ACT, sizeof(opt), &opt))
++              goto nla_put_failure;
++
++      if (nla_put_u16(skb, TCA_CTINFO_ZONE, cp->zone))
++              goto nla_put_failure;
++
++      if (cp->mode & CTINFO_MODE_DSCP) {
++              if (nla_put_u32(skb, TCA_CTINFO_PARMS_DSCP_MASK,
++                              cp->dscpmask))
++                      goto nla_put_failure;
++              if (nla_put_u32(skb, TCA_CTINFO_PARMS_DSCP_STATEMASK,
++                              cp->dscpstatemask))
++                      goto nla_put_failure;
++      }
++
++      if (cp->mode & CTINFO_MODE_CPMARK) {
++              if (nla_put_u32(skb, TCA_CTINFO_PARMS_CPMARK_MASK,
++                              cp->cpmarkmask))
++                      goto nla_put_failure;
++      }
++
++      if (nla_put_u64_64bit(skb, TCA_CTINFO_STATS_DSCP_SET,
++                            ci->stats_dscp_set, TCA_CTINFO_PAD))
++              goto nla_put_failure;
++
++      if (nla_put_u64_64bit(skb, TCA_CTINFO_STATS_DSCP_ERROR,
++                            ci->stats_dscp_error, TCA_CTINFO_PAD))
++              goto nla_put_failure;
++
++      if (nla_put_u64_64bit(skb, TCA_CTINFO_STATS_CPMARK_SET,
++                            ci->stats_cpmark_set, TCA_CTINFO_PAD))
++              goto nla_put_failure;
++
++      spin_unlock_bh(&ci->tcf_lock);
++      return skb->len;
++
++nla_put_failure:
++      spin_unlock_bh(&ci->tcf_lock);
++      nlmsg_trim(skb, b);
++      return -1;
++}
++
++static int tcf_ctinfo_walker(struct net *net, struct sk_buff *skb,
++                           struct netlink_callback *cb, int type,
++                           const struct tc_action_ops *ops,
++                           struct netlink_ext_ack *extack)
++{
++      struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
++
++      return tcf_generic_walker(tn, skb, cb, type, ops, extack);
++}
++
++static int tcf_ctinfo_search(struct net *net, struct tc_action **a, u32 index,
++                           struct netlink_ext_ack *extack)
++{
++      struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
++
++      return tcf_idr_search(tn, a, index);
++}
++
++static void tcf_ctinfo_cleanup(struct tc_action *a)
++{
++      struct tcf_ctinfo *ci = to_ctinfo(a);
++      struct tcf_ctinfo_params *cp;
++
++      cp = rcu_dereference_protected(ci->params, 1);
++      if (cp)
++              kfree_rcu(cp, rcu);
++}
++
++static struct tc_action_ops act_ctinfo_ops = {
++      .kind   = "ctinfo",
++      .type   = TCA_ID_CTINFO,
++      .owner  = THIS_MODULE,
++      .act    = tcf_ctinfo_act,
++      .dump   = tcf_ctinfo_dump,
++      .init   = tcf_ctinfo_init,
++      .walk   = tcf_ctinfo_walker,
++      .cleanup= tcf_ctinfo_cleanup,
++      .lookup = tcf_ctinfo_search,
++      .size   = sizeof(struct tcf_ctinfo),
++};
++
++static __net_init int ctinfo_init_net(struct net *net)
++{
++      struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
++
++      return tc_action_net_init(net, tn, &act_ctinfo_ops);
++}
++
++static void __net_exit ctinfo_exit_net(struct list_head *net_list)
++{
++      tc_action_net_exit(net_list, ctinfo_net_id);
++}
++
++static struct pernet_operations ctinfo_net_ops = {
++      .init           = ctinfo_init_net,
++      .exit_batch     = ctinfo_exit_net,
++      .id             = &ctinfo_net_id,
++      .size           = sizeof(struct tc_action_net),
++};
++
++static int __init ctinfo_init_module(void)
++{
++      return tcf_register_action(&act_ctinfo_ops, &ctinfo_net_ops);
++}
++
++static void __exit ctinfo_cleanup_module(void)
++{
++      tcf_unregister_action(&act_ctinfo_ops, &ctinfo_net_ops);
++}
++
++module_init(ctinfo_init_module);
++module_exit(ctinfo_cleanup_module);
++MODULE_AUTHOR("Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>");
++MODULE_DESCRIPTION("Connection tracking mark actions");
++MODULE_LICENSE("GPL");
+--- a/tools/testing/selftests/tc-testing/config
++++ b/tools/testing/selftests/tc-testing/config
+@@ -38,6 +38,7 @@ CONFIG_NET_ACT_CSUM=m
+ CONFIG_NET_ACT_VLAN=m
+ CONFIG_NET_ACT_BPF=m
+ CONFIG_NET_ACT_CONNMARK=m
++CONFIG_NET_ACT_CONNCTINFO=m
+ CONFIG_NET_ACT_SKBMOD=m
+ CONFIG_NET_ACT_IFE=m
+ CONFIG_NET_ACT_TUNNEL_KEY=m
diff --git a/target/linux/generic/backport-5.4/450-v5.0-mtd-spinand-winbond-Add-support-for-W25N01GV.patch b/target/linux/generic/backport-5.4/450-v5.0-mtd-spinand-winbond-Add-support-for-W25N01GV.patch
new file mode 100644 (file)
index 0000000..2024577
--- /dev/null
@@ -0,0 +1,37 @@
+From 9a4d83074769d6ecf1f5c3fef0f183b09abf3726 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Sat, 6 Oct 2018 17:36:42 +0200
+Subject: [PATCH 1/8] mtd: spinand: winbond: Add support for W25N01GV
+
+W25N01GV is a single die version of the already supported
+W25M02GV with half the capacity. Everything else is the
+same so introduce support for W25N01GV.
+
+Datasheet:http://www.winbond.com/resource-files/w25n01gv%20revl%20050918%20unsecured.pdf
+
+Tested on 8devices Jalapeno dev board under OpenWrt running 4.19-rc5.
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/winbond.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/mtd/nand/spi/winbond.c
++++ b/drivers/mtd/nand/spi/winbond.c
+@@ -84,6 +84,14 @@ static const struct spinand_info winbond
+                    0,
+                    SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
+                    SPINAND_SELECT_TARGET(w25m02gv_select_target)),
++      SPINAND_INFO("W25N01GV", 0xAA,
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(1, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+ };
+ /**
diff --git a/target/linux/generic/backport-5.4/451-v5.0-mtd-spinand-Add-initial-support-for-Toshiba-TC58CVG2.patch b/target/linux/generic/backport-5.4/451-v5.0-mtd-spinand-Add-initial-support-for-Toshiba-TC58CVG2.patch
new file mode 100644 (file)
index 0000000..ed42f00
--- /dev/null
@@ -0,0 +1,188 @@
+From 10949af1681d5bb5cdbcc012815c6e40eec17d02 Mon Sep 17 00:00:00 2001
+From: Schrempf Frieder <frieder.schrempf@kontron.De>
+Date: Thu, 8 Nov 2018 08:32:11 +0000
+Subject: [PATCH 2/8] mtd: spinand: Add initial support for Toshiba TC58CVG2S0H
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add minimal support for the Toshiba TC58CVG2S0H SPI NAND chip.
+
+Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+Acked-by: Clément Péron <peron.clem@gmail.com>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/Makefile  |   2 +-
+ drivers/mtd/nand/spi/core.c    |   1 +
+ drivers/mtd/nand/spi/toshiba.c | 137 +++++++++++++++++++++++++++++++++
+ include/linux/mtd/spinand.h    |   1 +
+ 4 files changed, 140 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/mtd/nand/spi/toshiba.c
+
+--- a/drivers/mtd/nand/spi/Makefile
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -1,3 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0
+-spinand-objs := core.o macronix.o micron.o winbond.o
++spinand-objs := core.o macronix.o micron.o toshiba.o winbond.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -764,6 +764,7 @@ static const struct nand_ops spinand_ops
+ static const struct spinand_manufacturer *spinand_manufacturers[] = {
+       &macronix_spinand_manufacturer,
+       &micron_spinand_manufacturer,
++      &toshiba_spinand_manufacturer,
+       &winbond_spinand_manufacturer,
+ };
+--- /dev/null
++++ b/drivers/mtd/nand/spi/toshiba.c
+@@ -0,0 +1,137 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (c) 2018 exceet electronics GmbH
++ * Copyright (c) 2018 Kontron Electronics GmbH
++ *
++ * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
++ */
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++#define SPINAND_MFR_TOSHIBA           0x98
++#define TOSH_STATUS_ECC_HAS_BITFLIPS_T        (3 << 4)
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++              SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++              SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++              SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                   struct mtd_oob_region *region)
++{
++      if (section > 7)
++              return -ERANGE;
++
++      region->offset = 128 + 16 * section;
++      region->length = 16;
++
++      return 0;
++}
++
++static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
++                                    struct mtd_oob_region *region)
++{
++      if (section > 0)
++              return -ERANGE;
++
++      /* 2 bytes reserved for BBM */
++      region->offset = 2;
++      region->length = 126;
++
++      return 0;
++}
++
++static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = {
++      .ecc = tc58cvg2s0h_ooblayout_ecc,
++      .free = tc58cvg2s0h_ooblayout_free,
++};
++
++static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
++                                    u8 status)
++{
++      struct nand_device *nand = spinand_to_nand(spinand);
++      u8 mbf = 0;
++      struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
++
++      switch (status & STATUS_ECC_MASK) {
++      case STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      case STATUS_ECC_HAS_BITFLIPS:
++      case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
++              /*
++               * Let's try to retrieve the real maximum number of bitflips
++               * in order to avoid forcing the wear-leveling layer to move
++               * data around if it's not necessary.
++               */
++              if (spi_mem_exec_op(spinand->spimem, &op))
++                      return nand->eccreq.strength;
++
++              mbf >>= 4;
++
++              if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
++                      return nand->eccreq.strength;
++
++              return mbf;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++
++static const struct spinand_info toshiba_spinand_table[] = {
++      SPINAND_INFO("TC58CVG2S0H", 0xCD,
++                   NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   SPINAND_HAS_QE_BIT,
++                   SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout,
++                                   tc58cvg2s0h_ecc_get_status)),
++};
++
++static int toshiba_spinand_detect(struct spinand_device *spinand)
++{
++      u8 *id = spinand->id.data;
++      int ret;
++
++      /*
++       * Toshiba SPI NAND read ID needs a dummy byte,
++       * so the first byte in id is garbage.
++       */
++      if (id[1] != SPINAND_MFR_TOSHIBA)
++              return 0;
++
++      ret = spinand_match_and_init(spinand, toshiba_spinand_table,
++                                   ARRAY_SIZE(toshiba_spinand_table),
++                                   id[2]);
++      if (ret)
++              return ret;
++
++      return 1;
++}
++
++static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
++      .detect = toshiba_spinand_detect,
++};
++
++const struct spinand_manufacturer toshiba_spinand_manufacturer = {
++      .id = SPINAND_MFR_TOSHIBA,
++      .name = "Toshiba",
++      .ops = &toshiba_spinand_manuf_ops,
++};
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -196,6 +196,7 @@ struct spinand_manufacturer {
+ /* SPI NAND manufacturers */
+ extern const struct spinand_manufacturer macronix_spinand_manufacturer;
+ extern const struct spinand_manufacturer micron_spinand_manufacturer;
++extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
+ extern const struct spinand_manufacturer winbond_spinand_manufacturer;
+ /**
diff --git a/target/linux/generic/backport-5.4/452-v5.0-mtd-spinand-add-support-for-GigaDevice-GD5FxGQ4xA.patch b/target/linux/generic/backport-5.4/452-v5.0-mtd-spinand-add-support-for-GigaDevice-GD5FxGQ4xA.patch
new file mode 100644 (file)
index 0000000..4e6f18a
--- /dev/null
@@ -0,0 +1,196 @@
+From c93c613214ac70c87beab5422a60077bf126b855 Mon Sep 17 00:00:00 2001
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Wed, 28 Nov 2018 21:07:25 +0800
+Subject: [PATCH 3/8] mtd: spinand: add support for GigaDevice GD5FxGQ4xA
+
+Add support for GigaDevice GD5F1G/2G/4GQ4xA SPI NAND.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/Makefile     |   2 +-
+ drivers/mtd/nand/spi/core.c       |   1 +
+ drivers/mtd/nand/spi/gigadevice.c | 148 ++++++++++++++++++++++++++++++
+ include/linux/mtd/spinand.h       |   1 +
+ 4 files changed, 151 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/mtd/nand/spi/gigadevice.c
+
+--- a/drivers/mtd/nand/spi/Makefile
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -1,3 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0
+-spinand-objs := core.o macronix.o micron.o toshiba.o winbond.o
++spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -762,6 +762,7 @@ static const struct nand_ops spinand_ops
+ };
+ static const struct spinand_manufacturer *spinand_manufacturers[] = {
++      &gigadevice_spinand_manufacturer,
+       &macronix_spinand_manufacturer,
+       &micron_spinand_manufacturer,
+       &toshiba_spinand_manufacturer,
+--- /dev/null
++++ b/drivers/mtd/nand/spi/gigadevice.c
+@@ -0,0 +1,148 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Author:
++ *    Chuanhong Guo <gch981213@gmail.com>
++ */
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++#define SPINAND_MFR_GIGADEVICE                        0xC8
++#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS    (1 << 4)
++#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS      (3 << 4)
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++              SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++              SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
++              SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++              SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
++              SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = (16 * section) + 8;
++      region->length = 8;
++
++      return 0;
++}
++
++static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
++                                 struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      if (section) {
++              region->offset = 16 * section;
++              region->length = 8;
++      } else {
++              /* section 0 has one byte reserved for bad block mark */
++              region->offset = 1;
++              region->length = 7;
++      }
++      return 0;
++}
++
++static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
++                                       u8 status)
++{
++      switch (status & STATUS_ECC_MASK) {
++      case STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
++              /* 1-7 bits are flipped. return the maximum. */
++              return 7;
++
++      case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
++              return 8;
++
++      case STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++
++static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
++      .ecc = gd5fxgq4xa_ooblayout_ecc,
++      .free = gd5fxgq4xa_ooblayout_free,
++};
++
++static const struct spinand_info gigadevice_spinand_table[] = {
++      SPINAND_INFO("GD5F1GQ4xA", 0xF1,
++                   NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
++                                   gd5fxgq4xa_ecc_get_status)),
++      SPINAND_INFO("GD5F2GQ4xA", 0xF2,
++                   NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
++                                   gd5fxgq4xa_ecc_get_status)),
++      SPINAND_INFO("GD5F4GQ4xA", 0xF4,
++                   NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
++                                   gd5fxgq4xa_ecc_get_status)),
++};
++
++static int gigadevice_spinand_detect(struct spinand_device *spinand)
++{
++      u8 *id = spinand->id.data;
++      int ret;
++
++      /*
++       * For GD NANDs, There is an address byte needed to shift in before IDs
++       * are read out, so the first byte in raw_id is dummy.
++       */
++      if (id[1] != SPINAND_MFR_GIGADEVICE)
++              return 0;
++
++      ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
++                                   ARRAY_SIZE(gigadevice_spinand_table),
++                                   id[2]);
++      if (ret)
++              return ret;
++
++      return 1;
++}
++
++static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
++      .detect = gigadevice_spinand_detect,
++};
++
++const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
++      .id = SPINAND_MFR_GIGADEVICE,
++      .name = "GigaDevice",
++      .ops = &gigadevice_spinand_manuf_ops,
++};
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -194,6 +194,7 @@ struct spinand_manufacturer {
+ };
+ /* SPI NAND manufacturers */
++extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+ extern const struct spinand_manufacturer macronix_spinand_manufacturer;
+ extern const struct spinand_manufacturer micron_spinand_manufacturer;
+ extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
diff --git a/target/linux/generic/backport-5.4/455-v5.1-mtd-spinand-Add-support-for-all-Toshiba-Memory-produ.patch b/target/linux/generic/backport-5.4/455-v5.1-mtd-spinand-Add-support-for-all-Toshiba-Memory-produ.patch
new file mode 100644 (file)
index 0000000..aad82dc
--- /dev/null
@@ -0,0 +1,136 @@
+From db214513f62fd13c0a9af3bd5c5d634dba37e65d Mon Sep 17 00:00:00 2001
+From: Yoshio Furuyama <tmcmc-mb-yfuruyama7@ml.toshiba.co.jp>
+Date: Wed, 16 Jan 2019 14:53:19 +0900
+Subject: [PATCH 7/8] mtd: spinand: Add support for all Toshiba Memory products
+
+Add device table for Toshiba Memory products.
+Also, generalize OOB layout structure and function names.
+
+Signed-off-by: Yoshio Furuyama <tmcmc-mb-yfuruyama7@ml.toshiba.co.jp>
+Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/toshiba.c | 79 ++++++++++++++++++++++++++++------
+ 1 file changed, 65 insertions(+), 14 deletions(-)
+
+--- a/drivers/mtd/nand/spi/toshiba.c
++++ b/drivers/mtd/nand/spi/toshiba.c
+@@ -25,19 +25,19 @@ static SPINAND_OP_VARIANTS(write_cache_v
+ static SPINAND_OP_VARIANTS(update_cache_variants,
+               SPINAND_PROG_LOAD(false, 0, NULL, 0));
+-static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section,
++static int tc58cxgxsx_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                    struct mtd_oob_region *region)
+ {
+-      if (section > 7)
++      if (section > 0)
+               return -ERANGE;
+-      region->offset = 128 + 16 * section;
+-      region->length = 16;
++      region->offset = mtd->oobsize / 2;
++      region->length = mtd->oobsize / 2;
+       return 0;
+ }
+-static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
++static int tc58cxgxsx_ooblayout_free(struct mtd_info *mtd, int section,
+                                     struct mtd_oob_region *region)
+ {
+       if (section > 0)
+@@ -45,17 +45,17 @@ static int tc58cvg2s0h_ooblayout_free(st
+       /* 2 bytes reserved for BBM */
+       region->offset = 2;
+-      region->length = 126;
++      region->length = (mtd->oobsize / 2) - 2;
+       return 0;
+ }
+-static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = {
+-      .ecc = tc58cvg2s0h_ooblayout_ecc,
+-      .free = tc58cvg2s0h_ooblayout_free,
++static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = {
++      .ecc = tc58cxgxsx_ooblayout_ecc,
++      .free = tc58cxgxsx_ooblayout_free,
+ };
+-static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
++static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
+                                     u8 status)
+ {
+       struct nand_device *nand = spinand_to_nand(spinand);
+@@ -94,15 +94,66 @@ static int tc58cvg2s0h_ecc_get_status(st
+ }
+ static const struct spinand_info toshiba_spinand_table[] = {
+-      SPINAND_INFO("TC58CVG2S0H", 0xCD,
++      /* 3.3V 1Gb */
++      SPINAND_INFO("TC58CVG0S3", 0xC2,
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
++                                   tc58cxgxsx_ecc_get_status)),
++      /* 3.3V 2Gb */
++      SPINAND_INFO("TC58CVG1S3", 0xCB,
++                   NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
++                                   tc58cxgxsx_ecc_get_status)),
++      /* 3.3V 4Gb */
++      SPINAND_INFO("TC58CVG2S0", 0xCD,
++                   NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
++                                   tc58cxgxsx_ecc_get_status)),
++      /* 1.8V 1Gb */
++      SPINAND_INFO("TC58CYG0S3", 0xB2,
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
++                                   tc58cxgxsx_ecc_get_status)),
++      /* 1.8V 2Gb */
++      SPINAND_INFO("TC58CYG1S3", 0xBB,
++                   NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
++                                   tc58cxgxsx_ecc_get_status)),
++      /* 1.8V 4Gb */
++      SPINAND_INFO("TC58CYG2S0", 0xBD,
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_ECCREQ(8, 512),
+                    SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+-                   SPINAND_HAS_QE_BIT,
+-                   SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout,
+-                                   tc58cvg2s0h_ecc_get_status)),
++                   0,
++                   SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
++                                   tc58cxgxsx_ecc_get_status)),
+ };
+ static int toshiba_spinand_detect(struct spinand_device *spinand)
diff --git a/target/linux/generic/backport-5.4/456-v5.1-mtd-spinand-Add-support-for-GigaDevice-GD5F1GQ4UExxG.patch b/target/linux/generic/backport-5.4/456-v5.1-mtd-spinand-Add-support-for-GigaDevice-GD5F1GQ4UExxG.patch
new file mode 100644 (file)
index 0000000..8e48deb
--- /dev/null
@@ -0,0 +1,129 @@
+From c40c7a990a46e5102a1cc4190557bf315d32d80d Mon Sep 17 00:00:00 2001
+From: Stefan Roese <sr@denx.de>
+Date: Thu, 24 Jan 2019 13:48:06 +0100
+Subject: [PATCH 8/8] mtd: spinand: Add support for GigaDevice GD5F1GQ4UExxG
+
+Add support for GigaDevice GD5F1GQ4UExxG SPI NAND chip.
+
+Signed-off-by: Stefan Roese <sr@denx.de>
+Cc: Chuanhong Guo <gch981213@gmail.com>
+Cc: Frieder Schrempf <frieder.schrempf@kontron.de>
+Cc: Miquel Raynal <miquel.raynal@bootlin.com>
+Cc: Boris Brezillon <bbrezillon@kernel.org>
+Reviewed-by: Boris Brezillon <bbrezillon@kernel.org>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/gigadevice.c | 83 +++++++++++++++++++++++++++++++
+ 1 file changed, 83 insertions(+)
+
+--- a/drivers/mtd/nand/spi/gigadevice.c
++++ b/drivers/mtd/nand/spi/gigadevice.c
+@@ -12,6 +12,8 @@
+ #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS    (1 << 4)
+ #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS      (3 << 4)
++#define GD5FXGQ4UEXXG_REG_STATUS2             0xf0
++
+ static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+@@ -81,11 +83,83 @@ static int gd5fxgq4xa_ecc_get_status(str
+       return -EINVAL;
+ }
++static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                     struct mtd_oob_region *region)
++{
++      if (section)
++              return -ERANGE;
++
++      region->offset = 64;
++      region->length = 64;
++
++      return 0;
++}
++
++static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
++                                      struct mtd_oob_region *region)
++{
++      if (section)
++              return -ERANGE;
++
++      /* Reserve 1 bytes for the BBM. */
++      region->offset = 1;
++      region->length = 63;
++
++      return 0;
++}
++
++static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
++                                      u8 status)
++{
++      u8 status2;
++      struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2,
++                                                    &status2);
++      int ret;
++
++      switch (status & STATUS_ECC_MASK) {
++      case STATUS_ECC_NO_BITFLIPS:
++              return 0;
++
++      case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
++              /*
++               * Read status2 register to determine a more fine grained
++               * bit error status
++               */
++              ret = spi_mem_exec_op(spinand->spimem, &op);
++              if (ret)
++                      return ret;
++
++              /*
++               * 4 ... 7 bits are flipped (1..4 can't be detected, so
++               * report the maximum of 4 in this case
++               */
++              /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
++              return ((status & STATUS_ECC_MASK) >> 2) |
++                      ((status2 & STATUS_ECC_MASK) >> 4);
++
++      case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
++              return 8;
++
++      case STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++
+ static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+       .ecc = gd5fxgq4xa_ooblayout_ecc,
+       .free = gd5fxgq4xa_ooblayout_free,
+ };
++static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
++      .ecc = gd5fxgq4uexxg_ooblayout_ecc,
++      .free = gd5fxgq4uexxg_ooblayout_free,
++};
++
+ static const struct spinand_info gigadevice_spinand_table[] = {
+       SPINAND_INFO("GD5F1GQ4xA", 0xF1,
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+@@ -114,6 +188,15 @@ static const struct spinand_info gigadev
+                    0,
+                    SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+                                    gd5fxgq4xa_ecc_get_status)),
++      SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
++                                   gd5fxgq4uexxg_ecc_get_status)),
+ };
+ static int gigadevice_spinand_detect(struct spinand_device *spinand)
diff --git a/target/linux/generic/backport-5.4/460-v5.0-mtd-spi-nor-Add-support-for-mx25u12835f.patch b/target/linux/generic/backport-5.4/460-v5.0-mtd-spi-nor-Add-support-for-mx25u12835f.patch
new file mode 100644 (file)
index 0000000..1bdf35b
--- /dev/null
@@ -0,0 +1,25 @@
+From 81554171373018b83f3554b9e725d2b5bf1844a5 Mon Sep 17 00:00:00 2001
+From: Alexander Sverdlin <alexander.sverdlin@nokia.com>
+Date: Fri, 13 Jul 2018 15:06:46 +0200
+Subject: [PATCH] mtd: spi-nor: Add support for mx25u12835f
+
+This chip supports dual and quad read and uniform 4K-byte erase.
+
+Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
+Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1088,6 +1088,8 @@ static const struct flash_info spi_nor_i
+       { "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+       { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+       { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
++      { "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
++                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+       { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
+       { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
diff --git a/target/linux/generic/backport-5.4/460-v5.3-mtd-spinand-Define-macros-for-page-read-ops-with-thr.patch b/target/linux/generic/backport-5.4/460-v5.3-mtd-spinand-Define-macros-for-page-read-ops-with-thr.patch
new file mode 100644 (file)
index 0000000..c28ae1d
--- /dev/null
@@ -0,0 +1,81 @@
+From d014717d50b1efd011a3a028ce92563a4dc9bae5 Mon Sep 17 00:00:00 2001
+From: Jeff Kletsky <git-commits@allycomm.com>
+Date: Wed, 22 May 2019 15:05:53 -0700
+Subject: [PATCH 1/3] mtd: spinand: Define macros for page-read ops with
+ three-byte addresses
+
+The GigaDevice GD5F1GQ4UFxxG SPI NAND utilizes three-byte addresses
+for its page-read ops.
+
+http://www.gigadevice.com/datasheet/gd5f1gq4xfxxg/
+
+Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
+Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ include/linux/mtd/spinand.h | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -68,30 +68,60 @@
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 1))
++#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len) \
++      SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1),               \
++                 SPI_MEM_OP_ADDR(3, addr, 1),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 1),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 1))
++
+ #define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len)    \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
+                  SPI_MEM_OP_ADDR(2, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 2))
++#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len) \
++      SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1),                             \
++                 SPI_MEM_OP_ADDR(3, addr, 1),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 1),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 2))
++
+ #define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len)    \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
+                  SPI_MEM_OP_ADDR(2, addr, 1),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 1),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 4))
++#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len) \
++      SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1),                             \
++                 SPI_MEM_OP_ADDR(3, addr, 1),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 1),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 4))
++
+ #define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len)        \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),                             \
+                  SPI_MEM_OP_ADDR(2, addr, 2),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 2),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 2))
++#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \
++      SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1),                             \
++                 SPI_MEM_OP_ADDR(3, addr, 2),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 2),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 2))
++
+ #define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len)        \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),                             \
+                  SPI_MEM_OP_ADDR(2, addr, 4),                         \
+                  SPI_MEM_OP_DUMMY(ndummy, 4),                         \
+                  SPI_MEM_OP_DATA_IN(len, buf, 4))
++#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \
++      SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1),                             \
++                 SPI_MEM_OP_ADDR(3, addr, 4),                         \
++                 SPI_MEM_OP_DUMMY(ndummy, 4),                         \
++                 SPI_MEM_OP_DATA_IN(len, buf, 4))
++
+ #define SPINAND_PROG_EXEC_OP(addr)                                    \
+       SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1),                             \
+                  SPI_MEM_OP_ADDR(3, addr, 1),                         \
diff --git a/target/linux/generic/backport-5.4/461-v5.3-mtd-spinand-Add-support-for-two-byte-device-IDs.patch b/target/linux/generic/backport-5.4/461-v5.3-mtd-spinand-Add-support-for-two-byte-device-IDs.patch
new file mode 100644 (file)
index 0000000..fcbecbb
--- /dev/null
@@ -0,0 +1,48 @@
+From 53dd94a79d3bfdaae30e5a4ebf474ea1af1d572e Mon Sep 17 00:00:00 2001
+From: Jeff Kletsky <git-commits@allycomm.com>
+Date: Wed, 22 May 2019 15:05:54 -0700
+Subject: [PATCH 2/3] mtd: spinand: Add support for two-byte device IDs
+
+The GigaDevice GD5F1GQ4UFxxG SPI NAND utilizes two-byte device IDs.
+
+http://www.gigadevice.com/datasheet/gd5f1gq4xfxxg/
+
+Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
+Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/core.c | 2 +-
+ include/linux/mtd/spinand.h | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -853,7 +853,7 @@ spinand_select_op_variant(struct spinand
+  */
+ int spinand_match_and_init(struct spinand_device *spinand,
+                          const struct spinand_info *table,
+-                         unsigned int table_size, u8 devid)
++                         unsigned int table_size, u16 devid)
+ {
+       struct nand_device *nand = spinand_to_nand(spinand);
+       unsigned int i;
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -290,7 +290,7 @@ struct spinand_ecc_info {
+  */
+ struct spinand_info {
+       const char *model;
+-      u8 devid;
++      u16 devid;
+       u32 flags;
+       struct nand_memory_organization memorg;
+       struct nand_ecc_req eccreq;
+@@ -445,7 +445,7 @@ static inline void spinand_set_of_node(s
+ int spinand_match_and_init(struct spinand_device *dev,
+                          const struct spinand_info *table,
+-                         unsigned int table_size, u8 devid);
++                         unsigned int table_size, u16 devid);
+ int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
+ int spinand_select_target(struct spinand_device *spinand, unsigned int target);
diff --git a/target/linux/generic/backport-5.4/462-v5.3-mtd-spinand-Add-support-for-GigaDevice-GD5F1GQ4UFxxG.patch b/target/linux/generic/backport-5.4/462-v5.3-mtd-spinand-Add-support-for-GigaDevice-GD5F1GQ4UFxxG.patch
new file mode 100644 (file)
index 0000000..06d87ba
--- /dev/null
@@ -0,0 +1,197 @@
+
+IMPORTANT NOTE
+==============
+
+The content of this patch has been adapted for Linux 4.19
+
+Changes were made in Linux 5.x to add the bad-block limit
+to the metadata available to the driver, adding a parameter
+
+NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+                                     ^- New bad-block limit
+
+This patch omits that parameter from the upstream patch
+for compatibility with the Linux 4.19 driver.
+
+=====
+
+From 049df13c4e63884fe6634db5568e08f65922256e Mon Sep 17 00:00:00 2001
+From: Jeff Kletsky <git-commits@allycomm.com>
+Date: Wed, 22 May 2019 15:05:55 -0700
+Subject: [PATCH 3/3] mtd: spinand: Add support for GigaDevice GD5F1GQ4UFxxG
+
+The GigaDevice GD5F1GQ4UFxxG SPI NAND is in current production devices
+and, while it has the same logical layout as the E-series devices,
+it differs in the SPI interfacing in significant ways.
+
+This support is contingent on previous commits to:
+
+  * Add support for two-byte device IDs
+  * Define macros for page-read ops with three-byte addresses
+
+http://www.gigadevice.com/datasheet/gd5f1gq4xfxxg/
+
+Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
+Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+---
+ drivers/mtd/nand/spi/gigadevice.c | 79 +++++++++++++++++++++++++------
+ 1 file changed, 64 insertions(+), 15 deletions(-)
+
+--- a/drivers/mtd/nand/spi/gigadevice.c
++++ b/drivers/mtd/nand/spi/gigadevice.c
+@@ -9,11 +9,17 @@
+ #include <linux/mtd/spinand.h>
+ #define SPINAND_MFR_GIGADEVICE                        0xC8
++
+ #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS    (1 << 4)
+ #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS      (3 << 4)
+ #define GD5FXGQ4UEXXG_REG_STATUS2             0xf0
++#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK                (7 << 4)
++#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
++#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS        (1 << 4)
++#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
++
+ static SPINAND_OP_VARIANTS(read_cache_variants,
+               SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+@@ -22,6 +28,14 @@ static SPINAND_OP_VARIANTS(read_cache_va
+               SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+               SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++static SPINAND_OP_VARIANTS(read_cache_variants_f,
++              SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
++
+ static SPINAND_OP_VARIANTS(write_cache_variants,
+               SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+               SPINAND_PROG_LOAD(true, 0, NULL, 0));
+@@ -59,6 +73,11 @@ static int gd5fxgq4xa_ooblayout_free(str
+       return 0;
+ }
++static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
++      .ecc = gd5fxgq4xa_ooblayout_ecc,
++      .free = gd5fxgq4xa_ooblayout_free,
++};
++
+ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
+                                        u8 status)
+ {
+@@ -83,7 +102,7 @@ static int gd5fxgq4xa_ecc_get_status(str
+       return -EINVAL;
+ }
+-static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
++static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                      struct mtd_oob_region *region)
+ {
+       if (section)
+@@ -95,7 +114,7 @@ static int gd5fxgq4uexxg_ooblayout_ecc(s
+       return 0;
+ }
+-static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
++static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
+                                       struct mtd_oob_region *region)
+ {
+       if (section)
+@@ -108,6 +127,11 @@ static int gd5fxgq4uexxg_ooblayout_free(
+       return 0;
+ }
++static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = {
++      .ecc = gd5fxgq4_variant2_ooblayout_ecc,
++      .free = gd5fxgq4_variant2_ooblayout_free,
++};
++
+ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
+                                       u8 status)
+ {
+@@ -150,15 +174,25 @@ static int gd5fxgq4uexxg_ecc_get_status(
+       return -EINVAL;
+ }
+-static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
+-      .ecc = gd5fxgq4xa_ooblayout_ecc,
+-      .free = gd5fxgq4xa_ooblayout_free,
+-};
++static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
++                                      u8 status)
++{
++      switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
++      case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
++              return 0;
+-static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
+-      .ecc = gd5fxgq4uexxg_ooblayout_ecc,
+-      .free = gd5fxgq4uexxg_ooblayout_free,
+-};
++      case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
++              return 3;
++
++      case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
++              return -EBADMSG;
++
++      default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
++              return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
++      }
++
++      return -EINVAL;
++}
+ static const struct spinand_info gigadevice_spinand_table[] = {
+       SPINAND_INFO("GD5F1GQ4xA", 0xF1,
+@@ -195,25 +229,40 @@ static const struct spinand_info gigadev
+                                             &write_cache_variants,
+                                             &update_cache_variants),
+                    0,
+-                   SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
++                   SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
+                                    gd5fxgq4uexxg_ecc_get_status)),
++      SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
++                                   gd5fxgq4ufxxg_ecc_get_status)),
+ };
+ static int gigadevice_spinand_detect(struct spinand_device *spinand)
+ {
+       u8 *id = spinand->id.data;
++      u16 did;
+       int ret;
+       /*
+-       * For GD NANDs, There is an address byte needed to shift in before IDs
+-       * are read out, so the first byte in raw_id is dummy.
++       * Earlier GDF5-series devices (A,E) return [0][MID][DID]
++       * Later (F) devices return [MID][DID1][DID2]
+        */
+-      if (id[1] != SPINAND_MFR_GIGADEVICE)
++
++      if (id[0] == SPINAND_MFR_GIGADEVICE)
++              did = (id[1] << 8) + id[2];
++      else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE)
++              did = id[2];
++      else
+               return 0;
+       ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
+                                    ARRAY_SIZE(gigadevice_spinand_table),
+-                                   id[2]);
++                                   did);
+       if (ret)
+               return ret;
diff --git a/target/linux/generic/backport-5.4/463-v5.3-mtd-spinand-Add-initial-support-for-Paragon-PN26G0xA.patch b/target/linux/generic/backport-5.4/463-v5.3-mtd-spinand-Add-initial-support-for-Paragon-PN26G0xA.patch
new file mode 100644 (file)
index 0000000..17b8e77
--- /dev/null
@@ -0,0 +1,203 @@
+From 3552691616c940a7c4125c2678ba816653cd725e Mon Sep 17 00:00:00 2001
+From: Jeff Kletsky <git-commits@allycomm.com>
+Date: Tue, 18 Jun 2019 10:08:05 -0700
+Subject: [PATCH] mtd: spinand: Add initial support for Paragon PN26G0xA
+
+Add initial support for Paragon Technology
+PN26G01Axxxxx and PN26G02Axxxxx SPI NAND
+
+Datasheets available at
+http://www.xtxtech.com/upfile/2016082517274590.pdf
+http://www.xtxtech.com/upfile/2016082517282329.pdf
+
+Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
+Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+
+ADOPTED FROM UPSTREAM  due to upstream commit 377e517b5fa5 in Linux 5.2
+                       which added another parameter to NAND_MEMORG
+---
+ drivers/mtd/nand/spi/Makefile  |   2 +-
+ drivers/mtd/nand/spi/core.c    |   1 +
+ drivers/mtd/nand/spi/paragon.c | 147 +++++++++++++++++++++++++++++++++
+ include/linux/mtd/spinand.h    |   1 +
+ 4 files changed, 150 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/mtd/nand/spi/paragon.c
+
+--- a/drivers/mtd/nand/spi/Makefile
++++ b/drivers/mtd/nand/spi/Makefile
+@@ -1,3 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0
+-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
++spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
+ obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
+--- a/drivers/mtd/nand/spi/core.c
++++ b/drivers/mtd/nand/spi/core.c
+@@ -765,6 +765,7 @@ static const struct spinand_manufacturer
+       &gigadevice_spinand_manufacturer,
+       &macronix_spinand_manufacturer,
+       &micron_spinand_manufacturer,
++      &paragon_spinand_manufacturer,
+       &toshiba_spinand_manufacturer,
+       &winbond_spinand_manufacturer,
+ };
+--- /dev/null
++++ b/drivers/mtd/nand/spi/paragon.c
+@@ -0,0 +1,147 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2019 Jeff Kletsky
++ *
++ * Author: Jeff Kletsky <git-commits@allycomm.com>
++ */
++
++#include <linux/device.h>
++#include <linux/kernel.h>
++#include <linux/mtd/spinand.h>
++
++
++#define SPINAND_MFR_PARAGON   0xa1
++
++
++#define PN26G0XA_STATUS_ECC_BITMASK           (3 << 4)
++
++#define PN26G0XA_STATUS_ECC_NONE_DETECTED     (0 << 4)
++#define PN26G0XA_STATUS_ECC_1_7_CORRECTED     (1 << 4)
++#define PN26G0XA_STATUS_ECC_ERRORED           (2 << 4)
++#define PN26G0XA_STATUS_ECC_8_CORRECTED               (3 << 4)
++
++
++static SPINAND_OP_VARIANTS(read_cache_variants,
++              SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++              SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(write_cache_variants,
++              SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
++              SPINAND_PROG_LOAD(true, 0, NULL, 0));
++
++static SPINAND_OP_VARIANTS(update_cache_variants,
++              SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
++              SPINAND_PROG_LOAD(false, 0, NULL, 0));
++
++
++static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
++                                 struct mtd_oob_region *region)
++{
++      if (section > 3)
++              return -ERANGE;
++
++      region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
++      region->length = 13;
++
++      return 0;
++}
++
++static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
++                                 struct mtd_oob_region *region)
++{
++      if (section > 4)
++              return -ERANGE;
++
++      if (section == 4) {
++              region->offset = 64;
++              region->length = 64;
++      } else {
++              region->offset = 4 + (15 * section);
++              region->length = 2;
++      }
++
++      return 0;
++}
++
++static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
++                                 u8 status)
++{
++      switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
++      case PN26G0XA_STATUS_ECC_NONE_DETECTED:
++              return 0;
++
++      case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
++              return 7;       /* Return upper limit by convention */
++
++      case PN26G0XA_STATUS_ECC_8_CORRECTED:
++              return 8;
++
++      case PN26G0XA_STATUS_ECC_ERRORED:
++              return -EBADMSG;
++
++      default:
++              break;
++      }
++
++      return -EINVAL;
++}
++
++static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
++      .ecc = pn26g0xa_ooblayout_ecc,
++      .free = pn26g0xa_ooblayout_free,
++};
++
++
++static const struct spinand_info paragon_spinand_table[] = {
++      SPINAND_INFO("PN26G01A", 0xe1,
++                   NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&pn26g0xa_ooblayout,
++                                   pn26g0xa_ecc_get_status)),
++      SPINAND_INFO("PN26G02A", 0xe2,
++                   NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
++                   NAND_ECCREQ(8, 512),
++                   SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++                                            &write_cache_variants,
++                                            &update_cache_variants),
++                   0,
++                   SPINAND_ECCINFO(&pn26g0xa_ooblayout,
++                                   pn26g0xa_ecc_get_status)),
++};
++
++static int paragon_spinand_detect(struct spinand_device *spinand)
++{
++      u8 *id = spinand->id.data;
++      int ret;
++
++      /* Read ID returns [0][MID][DID] */
++
++      if (id[1] != SPINAND_MFR_PARAGON)
++              return 0;
++
++      ret = spinand_match_and_init(spinand, paragon_spinand_table,
++                                   ARRAY_SIZE(paragon_spinand_table),
++                                   id[2]);
++      if (ret)
++              return ret;
++
++      return 1;
++}
++
++static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
++      .detect = paragon_spinand_detect,
++};
++
++const struct spinand_manufacturer paragon_spinand_manufacturer = {
++      .id = SPINAND_MFR_PARAGON,
++      .name = "Paragon",
++      .ops = &paragon_spinand_manuf_ops,
++};
+--- a/include/linux/mtd/spinand.h
++++ b/include/linux/mtd/spinand.h
+@@ -227,6 +227,7 @@ struct spinand_manufacturer {
+ extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+ extern const struct spinand_manufacturer macronix_spinand_manufacturer;
+ extern const struct spinand_manufacturer micron_spinand_manufacturer;
++extern const struct spinand_manufacturer paragon_spinand_manufacturer;
+ extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
+ extern const struct spinand_manufacturer winbond_spinand_manufacturer;
diff --git a/target/linux/generic/backport-5.4/700-v5.1-net-phylink-only-call-mac_config-during-resolve-when.patch b/target/linux/generic/backport-5.4/700-v5.1-net-phylink-only-call-mac_config-during-resolve-when.patch
new file mode 100644 (file)
index 0000000..0e272ea
--- /dev/null
@@ -0,0 +1,44 @@
+From 6f3ea4e5b1f0867ec217f6101fcb89783ed905d7 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sat, 9 Feb 2019 18:23:26 +0000
+Subject: [PATCH] net: phylink: only call mac_config() during resolve
+ when link is up
+
+There's little point calling mac_config() when the link is down.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -339,6 +339,13 @@ static void phylink_mac_config(struct ph
+       pl->ops->mac_config(pl->netdev, pl->link_an_mode, state);
+ }
++static void phylink_mac_config_up(struct phylink *pl,
++                                const struct phylink_link_state *state)
++{
++      if (state->link)
++              phylink_mac_config(pl, state);
++}
++
+ static void phylink_mac_an_restart(struct phylink *pl)
+ {
+       if (pl->link_config.an_enabled &&
+@@ -442,12 +449,12 @@ static void phylink_resolve(struct work_
+               case MLO_AN_PHY:
+                       link_state = pl->phy_state;
+                       phylink_resolve_flow(pl, &link_state);
+-                      phylink_mac_config(pl, &link_state);
++                      phylink_mac_config_up(pl, &link_state);
+                       break;
+               case MLO_AN_FIXED:
+                       phylink_get_fixed_state(pl, &link_state);
+-                      phylink_mac_config(pl, &link_state);
++                      phylink_mac_config_up(pl, &link_state);
+                       break;
+               case MLO_AN_INBAND:
diff --git a/target/linux/generic/backport-5.4/701-v5.2-net-phylink-ensure-inband-AN-works-correctly.patch b/target/linux/generic/backport-5.4/701-v5.2-net-phylink-ensure-inband-AN-works-correctly.patch
new file mode 100644 (file)
index 0000000..746aca2
--- /dev/null
@@ -0,0 +1,59 @@
+From 72f973f292b3eaaf451ebcd3253900d41f4ef24a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 25 Jan 2019 17:42:51 +0000
+Subject: [PATCH] net: phylink: ensure inband AN works correctly
+
+Do not update the link interface mode while the link is down to avoid
+spurious link interface changes.
+
+Always call mac_config if we have a PHY to propagate the pause mode
+settings to the MAC.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 37 +++++++++++++++----------------------
+ 1 file changed, 15 insertions(+), 22 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -459,28 +459,21 @@ static void phylink_resolve(struct work_
+               case MLO_AN_INBAND:
+                       phylink_get_mac_state(pl, &link_state);
+-                      if (pl->phydev) {
+-                              bool changed = false;
+-                              link_state.link = link_state.link &&
+-                                                pl->phy_state.link;
++                      /* If we have a phy, the "up" state is the union of
++                       * both the PHY and the MAC */
++                      if (pl->phydev)
++                              link_state.link &= pl->phy_state.link;
+-                              if (pl->phy_state.interface !=
+-                                  link_state.interface) {
+-                                      link_state.interface = pl->phy_state.interface;
+-                                      changed = true;
+-                              }
++                      /* Only update if the PHY link is up */
++                      if (pl->phydev && pl->phy_state.link) {
++                              link_state.interface = pl->phy_state.interface;
+-                              /* Propagate the flow control from the PHY
+-                               * to the MAC. Also propagate the interface
+-                               * if changed.
+-                               */
+-                              if (pl->phy_state.link || changed) {
+-                                      link_state.pause |= pl->phy_state.pause;
+-                                      phylink_resolve_flow(pl, &link_state);
+-
+-                                      phylink_mac_config(pl, &link_state);
+-                              }
++                              /* If we have a PHY, we need to update with
++                               * the pause mode bits. */
++                              link_state.pause |= pl->phy_state.pause;
++                              phylink_resolve_flow(pl, &link_state);
++                              phylink_mac_config(pl, &link_state);
+                       }
+                       break;
+               }
diff --git a/target/linux/generic/backport-5.4/702-v4.20-net-ethernet-Add-helper-for-MACs-which-support-asym-.patch b/target/linux/generic/backport-5.4/702-v4.20-net-ethernet-Add-helper-for-MACs-which-support-asym-.patch
new file mode 100644 (file)
index 0000000..3ada516
--- /dev/null
@@ -0,0 +1,49 @@
+From 1da223db3a0c522300b519ecbe1dc45927e28088 Mon Sep 17 00:00:00 2001
+From: Andrew Lunn <andrew@lunn.ch>
+Date: Wed, 12 Sep 2018 01:53:15 +0200
+Subject: [PATCH 600/660] net: ethernet: Add helper for MACs which support asym
+ pause
+
+Rather than have the MAC drivers manipulate phydev members to indicate
+they support Asym Pause, add a helper function.
+
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phy_device.c | 13 +++++++++++++
+ include/linux/phy.h          |  1 +
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1777,6 +1777,19 @@ int phy_set_max_speed(struct phy_device
+ }
+ EXPORT_SYMBOL(phy_set_max_speed);
++/**
++ * phy_support_asym_pause - Enable support of asym pause
++ * @phydev: target phy_device struct
++ *
++ * Description: Called by the MAC to indicate is supports Asym Pause.
++ */
++void phy_support_asym_pause(struct phy_device *phydev)
++{
++      phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
++      phydev->advertising = phydev->supported;
++}
++EXPORT_SYMBOL(phy_support_asym_pause);
++
+ static void of_set_phy_supported(struct phy_device *phydev)
+ {
+       struct device_node *node = phydev->mdio.dev.of_node;
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -1049,6 +1049,7 @@ int phy_mii_ioctl(struct phy_device *phy
+ int phy_start_interrupts(struct phy_device *phydev);
+ void phy_print_status(struct phy_device *phydev);
+ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
++void phy_support_asym_pause(struct phy_device *phydev);
+ int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
+                      int (*run)(struct phy_device *));
diff --git a/target/linux/generic/backport-5.4/703-v4.20-net-ethernet-Add-helper-for-set_pauseparam-for-Asym-.patch b/target/linux/generic/backport-5.4/703-v4.20-net-ethernet-Add-helper-for-set_pauseparam-for-Asym-.patch
new file mode 100644 (file)
index 0000000..4ad3bf6
--- /dev/null
@@ -0,0 +1,66 @@
+From ce825df56e0480a2cbb296e38976babafb57e503 Mon Sep 17 00:00:00 2001
+From: Andrew Lunn <andrew@lunn.ch>
+Date: Wed, 12 Sep 2018 01:53:17 +0200
+Subject: [PATCH 601/660] net: ethernet: Add helper for set_pauseparam for Asym
+ Pause
+
+ethtool can be used to enable/disable pause. Add a helper to configure
+the PHY when asym pause is supported.
+
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phy_device.c | 30 ++++++++++++++++++++++++++++++
+ include/linux/phy.h          |  1 +
+ 2 files changed, 31 insertions(+)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -1790,6 +1790,36 @@ void phy_support_asym_pause(struct phy_d
+ }
+ EXPORT_SYMBOL(phy_support_asym_pause);
++/**
++ * phy_set_asym_pause - Configure Pause and Asym Pause
++ * @phydev: target phy_device struct
++ * @rx: Receiver Pause is supported
++ * @tx: Transmit Pause is supported
++ *
++ * Description: Configure advertised Pause support depending on if
++ * transmit and receiver pause is supported. If there has been a
++ * change in adverting, trigger a new autoneg. Generally called from
++ * the set_pauseparam .ndo.
++ */
++void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx)
++{
++      u16 oldadv = phydev->advertising;
++      u16 newadv = oldadv &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
++
++      if (rx)
++              newadv |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
++      if (tx)
++              newadv ^= SUPPORTED_Asym_Pause;
++
++      if (oldadv != newadv) {
++              phydev->advertising = newadv;
++
++              if (phydev->autoneg)
++                      phy_start_aneg(phydev);
++      }
++}
++EXPORT_SYMBOL(phy_set_asym_pause);
++
+ static void of_set_phy_supported(struct phy_device *phydev)
+ {
+       struct device_node *node = phydev->mdio.dev.of_node;
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -1050,6 +1050,7 @@ int phy_start_interrupts(struct phy_devi
+ void phy_print_status(struct phy_device *phydev);
+ int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
+ void phy_support_asym_pause(struct phy_device *phydev);
++void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx);
+ int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
+                      int (*run)(struct phy_device *));
diff --git a/target/linux/generic/backport-5.4/704-v4.20-net-phy-Stop-with-excessive-soft-reset.patch b/target/linux/generic/backport-5.4/704-v4.20-net-phy-Stop-with-excessive-soft-reset.patch
new file mode 100644 (file)
index 0000000..00ef6b7
--- /dev/null
@@ -0,0 +1,40 @@
+From 1541649a9dd79e9b941d399de564475e426a2d0b Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli@gmail.com>
+Date: Tue, 25 Sep 2018 11:28:45 -0700
+Subject: [PATCH 602/660] net: phy: Stop with excessive soft reset
+
+While consolidating the PHY reset in phy_init_hw() an unconditionaly
+BMCR soft-reset I became quite trigger happy with those. This was later
+on deactivated for the Generic PHY driver on the premise that a prior
+software entity (e.g: bootloader) might have applied workarounds in
+commit 0878fff1f42c ("net: phy: Do not perform software reset for
+Generic PHY").
+
+Since we have a hook to wire-up a soft_reset callback, just use that and
+get rid of the call to genphy_soft_reset() entirely. This speeds up
+initialization and link establishment for most PHYs out there that do
+not require a reset.
+
+Fixes: 87aa9f9c61ad ("net: phy: consolidate PHY reset in phy_init_hw()")
+Tested-by: Wang, Dongsheng <dongsheng.wang@hxt-semitech.com>
+Tested-by: Chris Healy <cphealy@gmail.com>
+Tested-by: Andrew Lunn <andrew@lunn.ch>
+Tested-by: Clemens Gruber <clemens.gruber@pqgruber.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phy_device.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -886,8 +886,6 @@ int phy_init_hw(struct phy_device *phyde
+       if (phydev->drv->soft_reset)
+               ret = phydev->drv->soft_reset(phydev);
+-      else
+-              ret = genphy_soft_reset(phydev);
+       if (ret < 0)
+               return ret;
diff --git a/target/linux/generic/backport-5.4/705-v5.1-net-phy-provide-full-set-of-accessor-functions-to-MM.patch b/target/linux/generic/backport-5.4/705-v5.1-net-phy-provide-full-set-of-accessor-functions-to-MM.patch
new file mode 100644 (file)
index 0000000..9a587ad
--- /dev/null
@@ -0,0 +1,375 @@
+From 80758d9542205cd2e9fa730067bc3888d4f5a096 Mon Sep 17 00:00:00 2001
+From: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+Date: Wed, 6 Feb 2019 07:36:40 +0100
+Subject: [PATCH 603/660] net: phy: provide full set of accessor functions to
+ MMD registers
+
+This adds full set of locked and unlocked accessor functions to read and
+write PHY MMD registers and/or bitfields.
+
+Set of functions exactly matches what is already available for PHY
+legacy registers.
+
+Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+Signed-off-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phy-core.c | 116 ++++++++++++++++++++++++++++----
+ include/linux/phy.h        | 134 ++++++++++++++++++++++++++++++-------
+ 2 files changed, 214 insertions(+), 36 deletions(-)
+
+--- a/drivers/net/phy/phy-core.c
++++ b/drivers/net/phy/phy-core.c
+@@ -247,15 +247,15 @@ static void mmd_phy_indirect(struct mii_
+ }
+ /**
+- * phy_read_mmd - Convenience function for reading a register
++ * __phy_read_mmd - Convenience function for reading a register
+  * from an MMD on a given PHY.
+  * @phydev: The phy_device struct
+  * @devad: The MMD to read from (0..31)
+  * @regnum: The register on the MMD to read (0..65535)
+  *
+- * Same rules as for phy_read();
++ * Same rules as for __phy_read();
+  */
+-int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
++int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
+ {
+       int val;
+@@ -267,33 +267,52 @@ int phy_read_mmd(struct phy_device *phyd
+       } else if (phydev->is_c45) {
+               u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
+-              val = mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
++              val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
+       } else {
+               struct mii_bus *bus = phydev->mdio.bus;
+               int phy_addr = phydev->mdio.addr;
+-              mutex_lock(&bus->mdio_lock);
+               mmd_phy_indirect(bus, phy_addr, devad, regnum);
+               /* Read the content of the MMD's selected register */
+               val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
+-              mutex_unlock(&bus->mdio_lock);
+       }
+       return val;
+ }
++EXPORT_SYMBOL(__phy_read_mmd);
++
++/**
++ * phy_read_mmd - Convenience function for reading a register
++ * from an MMD on a given PHY.
++ * @phydev: The phy_device struct
++ * @devad: The MMD to read from
++ * @regnum: The register on the MMD to read
++ *
++ * Same rules as for phy_read();
++ */
++int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
++{
++      int ret;
++
++      mutex_lock(&phydev->mdio.bus->mdio_lock);
++      ret = __phy_read_mmd(phydev, devad, regnum);
++      mutex_unlock(&phydev->mdio.bus->mdio_lock);
++
++      return ret;
++}
+ EXPORT_SYMBOL(phy_read_mmd);
+ /**
+- * phy_write_mmd - Convenience function for writing a register
++ * __phy_write_mmd - Convenience function for writing a register
+  * on an MMD on a given PHY.
+  * @phydev: The phy_device struct
+  * @devad: The MMD to read from
+  * @regnum: The register on the MMD to read
+  * @val: value to write to @regnum
+  *
+- * Same rules as for phy_write();
++ * Same rules as for __phy_write();
+  */
+-int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
++int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
+ {
+       int ret;
+@@ -305,23 +324,43 @@ int phy_write_mmd(struct phy_device *phy
+       } else if (phydev->is_c45) {
+               u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
+-              ret = mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
+-                                  addr, val);
++              ret = __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
++                                    addr, val);
+       } else {
+               struct mii_bus *bus = phydev->mdio.bus;
+               int phy_addr = phydev->mdio.addr;
+-              mutex_lock(&bus->mdio_lock);
+               mmd_phy_indirect(bus, phy_addr, devad, regnum);
+               /* Write the data into MMD's selected register */
+               __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
+-              mutex_unlock(&bus->mdio_lock);
+               ret = 0;
+       }
+       return ret;
+ }
++EXPORT_SYMBOL(__phy_write_mmd);
++
++/**
++ * phy_write_mmd - Convenience function for writing a register
++ * on an MMD on a given PHY.
++ * @phydev: The phy_device struct
++ * @devad: The MMD to read from
++ * @regnum: The register on the MMD to read
++ * @val: value to write to @regnum
++ *
++ * Same rules as for phy_write();
++ */
++int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
++{
++      int ret;
++
++      mutex_lock(&phydev->mdio.bus->mdio_lock);
++      ret = __phy_write_mmd(phydev, devad, regnum, val);
++      mutex_unlock(&phydev->mdio.bus->mdio_lock);
++
++      return ret;
++}
+ EXPORT_SYMBOL(phy_write_mmd);
+ /**
+@@ -371,6 +410,57 @@ int phy_modify(struct phy_device *phydev
+ }
+ EXPORT_SYMBOL_GPL(phy_modify);
++/**
++ * __phy_modify_mmd - Convenience function for modifying a register on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @mask: bit mask of bits to clear
++ * @set: new value of bits set in mask to write to @regnum
++ *
++ * Unlocked helper function which allows a MMD register to be modified as
++ * new register value = (old register value & ~mask) | set
++ */
++int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
++                   u16 mask, u16 set)
++{
++      int ret;
++
++      ret = __phy_read_mmd(phydev, devad, regnum);
++      if (ret < 0)
++              return ret;
++
++      ret = __phy_write_mmd(phydev, devad, regnum, (ret & ~mask) | set);
++
++      return ret < 0 ? ret : 0;
++}
++EXPORT_SYMBOL_GPL(__phy_modify_mmd);
++
++/**
++ * phy_modify_mmd - Convenience function for modifying a register on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @mask: bit mask of bits to clear
++ * @set: new value of bits set in mask to write to @regnum
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
++                 u16 mask, u16 set)
++{
++      int ret;
++
++      mutex_lock(&phydev->mdio.bus->mdio_lock);
++      ret = __phy_modify_mmd(phydev, devad, regnum, mask, set);
++      mutex_unlock(&phydev->mdio.bus->mdio_lock);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(phy_modify_mmd);
++
+ static int __phy_read_page(struct phy_device *phydev)
+ {
+       return phydev->drv->read_page(phydev);
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -695,17 +695,6 @@ size_t phy_speeds(unsigned int *speeds,
+ void phy_resolve_aneg_linkmode(struct phy_device *phydev);
+ /**
+- * phy_read_mmd - Convenience function for reading a register
+- * from an MMD on a given PHY.
+- * @phydev: The phy_device struct
+- * @devad: The MMD to read from
+- * @regnum: The register on the MMD to read
+- *
+- * Same rules as for phy_read();
+- */
+-int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum);
+-
+-/**
+  * phy_read - Convenience function for reading a given PHY register
+  * @phydev: the phy_device struct
+  * @regnum: register number to read
+@@ -760,9 +749,60 @@ static inline int __phy_write(struct phy
+                              val);
+ }
++/**
++ * phy_read_mmd - Convenience function for reading a register
++ * from an MMD on a given PHY.
++ * @phydev: The phy_device struct
++ * @devad: The MMD to read from
++ * @regnum: The register on the MMD to read
++ *
++ * Same rules as for phy_read();
++ */
++int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum);
++
++/**
++ * __phy_read_mmd - Convenience function for reading a register
++ * from an MMD on a given PHY.
++ * @phydev: The phy_device struct
++ * @devad: The MMD to read from
++ * @regnum: The register on the MMD to read
++ *
++ * Same rules as for __phy_read();
++ */
++int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum);
++
++/**
++ * phy_write_mmd - Convenience function for writing a register
++ * on an MMD on a given PHY.
++ * @phydev: The phy_device struct
++ * @devad: The MMD to write to
++ * @regnum: The register on the MMD to read
++ * @val: value to write to @regnum
++ *
++ * Same rules as for phy_write();
++ */
++int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
++
++/**
++ * __phy_write_mmd - Convenience function for writing a register
++ * on an MMD on a given PHY.
++ * @phydev: The phy_device struct
++ * @devad: The MMD to write to
++ * @regnum: The register on the MMD to read
++ * @val: value to write to @regnum
++ *
++ * Same rules as for __phy_write();
++ */
++int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
++
+ int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
+ int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
++int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
++              u16 mask, u16 set);
++int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
++              u16 mask, u16 set);
++
+ /**
+  * __phy_set_bits - Convenience function for setting bits in a PHY register
+  * @phydev: the phy_device struct
+@@ -813,6 +853,66 @@ static inline int phy_clear_bits(struct
+ }
+ /**
++ * __phy_set_bits_mmd - Convenience function for setting bits in a register
++ * on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @val: bits to set
++ *
++ * The caller must have taken the MDIO bus lock.
++ */
++static inline int __phy_set_bits_mmd(struct phy_device *phydev, int devad,
++              u32 regnum, u16 val)
++{
++      return __phy_modify_mmd(phydev, devad, regnum, 0, val);
++}
++
++/**
++ * __phy_clear_bits_mmd - Convenience function for clearing bits in a register
++ * on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @val: bits to clear
++ *
++ * The caller must have taken the MDIO bus lock.
++ */
++static inline int __phy_clear_bits_mmd(struct phy_device *phydev, int devad,
++              u32 regnum, u16 val)
++{
++      return __phy_modify_mmd(phydev, devad, regnum, val, 0);
++}
++
++/**
++ * phy_set_bits_mmd - Convenience function for setting bits in a register
++ * on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @val: bits to set
++ */
++static inline int phy_set_bits_mmd(struct phy_device *phydev, int devad,
++              u32 regnum, u16 val)
++{
++      return phy_modify_mmd(phydev, devad, regnum, 0, val);
++}
++
++/**
++ * phy_clear_bits_mmd - Convenience function for clearing bits in a register
++ * on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @val: bits to clear
++ */
++static inline int phy_clear_bits_mmd(struct phy_device *phydev, int devad,
++              u32 regnum, u16 val)
++{
++      return phy_modify_mmd(phydev, devad, regnum, val, 0);
++}
++
++/**
+  * phy_interrupt_is_valid - Convenience function for testing a given PHY irq
+  * @phydev: the phy_device struct
+  *
+@@ -888,18 +988,6 @@ static inline bool phy_is_pseudo_fixed_l
+       return phydev->is_pseudo_fixed_link;
+ }
+-/**
+- * phy_write_mmd - Convenience function for writing a register
+- * on an MMD on a given PHY.
+- * @phydev: The phy_device struct
+- * @devad: The MMD to read from
+- * @regnum: The register on the MMD to read
+- * @val: value to write to @regnum
+- *
+- * Same rules as for phy_write();
+- */
+-int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
+-
+ int phy_save_page(struct phy_device *phydev);
+ int phy_select_page(struct phy_device *phydev, int page);
+ int phy_restore_page(struct phy_device *phydev, int oldpage, int ret);
diff --git a/target/linux/generic/backport-5.4/706-v5.1-net-phy-add-register-modifying-helpers-returning-1-o.patch b/target/linux/generic/backport-5.4/706-v5.1-net-phy-add-register-modifying-helpers-returning-1-o.patch
new file mode 100644 (file)
index 0000000..dddfcc2
--- /dev/null
@@ -0,0 +1,217 @@
+From c1e3f753f6b85d7636024159bb78f764e09492f1 Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1@gmail.com>
+Date: Sun, 10 Feb 2019 19:57:56 +0100
+Subject: [PATCH 604/660] net: phy: add register modifying helpers returning 1
+ on change
+
+When modifying registers there are scenarios where we need to know
+whether the register content actually changed. This patch adds
+new helpers to not break users of the current ones, phy_modify() etc.
+
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phy-core.c | 127 ++++++++++++++++++++++++++++++++++---
+ include/linux/phy.h        |  12 +++-
+ 2 files changed, 128 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/phy/phy-core.c
++++ b/drivers/net/phy/phy-core.c
+@@ -364,7 +364,7 @@ int phy_write_mmd(struct phy_device *phy
+ EXPORT_SYMBOL(phy_write_mmd);
+ /**
+- * __phy_modify() - Convenience function for modifying a PHY register
++ * __phy_modify_changed() - Convenience function for modifying a PHY register
+  * @phydev: a pointer to a &struct phy_device
+  * @regnum: register number
+  * @mask: bit mask of bits to clear
+@@ -372,16 +372,69 @@ EXPORT_SYMBOL(phy_write_mmd);
+  *
+  * Unlocked helper function which allows a PHY register to be modified as
+  * new register value = (old register value & ~mask) | set
++ *
++ * Returns negative errno, 0 if there was no change, and 1 in case of change
+  */
+-int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
++int __phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask,
++                       u16 set)
+ {
+-      int ret;
++      int new, ret;
+       ret = __phy_read(phydev, regnum);
+       if (ret < 0)
+               return ret;
+-      ret = __phy_write(phydev, regnum, (ret & ~mask) | set);
++      new = (ret & ~mask) | set;
++      if (new == ret)
++              return 0;
++
++      ret = __phy_write(phydev, regnum, new);
++
++      return ret < 0 ? ret : 1;
++}
++EXPORT_SYMBOL_GPL(__phy_modify_changed);
++
++/**
++ * phy_modify_changed - Function for modifying a PHY register
++ * @phydev: the phy_device struct
++ * @regnum: register number to modify
++ * @mask: bit mask of bits to clear
++ * @set: new value of bits set in mask to write to @regnum
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ *
++ * Returns negative errno, 0 if there was no change, and 1 in case of change
++ */
++int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
++{
++      int ret;
++
++      mutex_lock(&phydev->mdio.bus->mdio_lock);
++      ret = __phy_modify_changed(phydev, regnum, mask, set);
++      mutex_unlock(&phydev->mdio.bus->mdio_lock);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(phy_modify_changed);
++
++/**
++ * __phy_modify - Convenience function for modifying a PHY register
++ * @phydev: the phy_device struct
++ * @regnum: register number to modify
++ * @mask: bit mask of bits to clear
++ * @set: new value of bits set in mask to write to @regnum
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
++{
++      int ret;
++
++      ret = __phy_modify_changed(phydev, regnum, mask, set);
+       return ret < 0 ? ret : 0;
+ }
+@@ -411,7 +464,7 @@ int phy_modify(struct phy_device *phydev
+ EXPORT_SYMBOL_GPL(phy_modify);
+ /**
+- * __phy_modify_mmd - Convenience function for modifying a register on MMD
++ * __phy_modify_mmd_changed - Function for modifying a register on MMD
+  * @phydev: the phy_device struct
+  * @devad: the MMD containing register to modify
+  * @regnum: register number to modify
+@@ -420,17 +473,73 @@ EXPORT_SYMBOL_GPL(phy_modify);
+  *
+  * Unlocked helper function which allows a MMD register to be modified as
+  * new register value = (old register value & ~mask) | set
++ *
++ * Returns negative errno, 0 if there was no change, and 1 in case of change
+  */
+-int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
+-                   u16 mask, u16 set)
++int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
++                           u16 mask, u16 set)
+ {
+-      int ret;
++      int new, ret;
+       ret = __phy_read_mmd(phydev, devad, regnum);
+       if (ret < 0)
+               return ret;
+-      ret = __phy_write_mmd(phydev, devad, regnum, (ret & ~mask) | set);
++      new = (ret & ~mask) | set;
++      if (new == ret)
++              return 0;
++
++      ret = __phy_write_mmd(phydev, devad, regnum, new);
++
++      return ret < 0 ? ret : 1;
++}
++EXPORT_SYMBOL_GPL(__phy_modify_mmd_changed);
++
++/**
++ * phy_modify_mmd_changed - Function for modifying a register on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @mask: bit mask of bits to clear
++ * @set: new value of bits set in mask to write to @regnum
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ *
++ * Returns negative errno, 0 if there was no change, and 1 in case of change
++ */
++int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
++                         u16 mask, u16 set)
++{
++      int ret;
++
++      mutex_lock(&phydev->mdio.bus->mdio_lock);
++      ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
++      mutex_unlock(&phydev->mdio.bus->mdio_lock);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(phy_modify_mmd_changed);
++
++/**
++ * __phy_modify_mmd - Convenience function for modifying a register on MMD
++ * @phydev: the phy_device struct
++ * @devad: the MMD containing register to modify
++ * @regnum: register number to modify
++ * @mask: bit mask of bits to clear
++ * @set: new value of bits set in mask to write to @regnum
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
++                   u16 mask, u16 set)
++{
++      int ret;
++
++      ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
+       return ret < 0 ? ret : 0;
+ }
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -795,13 +795,21 @@ int phy_write_mmd(struct phy_device *phy
+  */
+ int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
++int __phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask,
++                       u16 set);
++int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask,
++                     u16 set);
+ int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
+ int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
++int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
++                           u16 mask, u16 set);
++int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
++                         u16 mask, u16 set);
+ int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
+-              u16 mask, u16 set);
++                   u16 mask, u16 set);
+ int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
+-              u16 mask, u16 set);
++                 u16 mask, u16 set);
+ /**
+  * __phy_set_bits - Convenience function for setting bits in a PHY register
diff --git a/target/linux/generic/backport-5.4/707-v5.1-net-phy-add-genphy_c45_check_and_restart_aneg.patch b/target/linux/generic/backport-5.4/707-v5.1-net-phy-add-genphy_c45_check_and_restart_aneg.patch
new file mode 100644 (file)
index 0000000..6d47fa9
--- /dev/null
@@ -0,0 +1,64 @@
+From 2c3db705737cf52d7d24c993f0889b25b956c718 Mon Sep 17 00:00:00 2001
+From: Heiner Kallweit <hkallweit1@gmail.com>
+Date: Mon, 18 Feb 2019 21:27:18 +0100
+Subject: [PATCH 605/660] net: phy: add genphy_c45_check_and_restart_aneg
+
+This function will be used by config_aneg callback implementations of
+PHY drivers and allows to reduce boilerplate code.
+
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phy-c45.c | 30 ++++++++++++++++++++++++++++++
+ include/linux/phy.h       |  1 +
+ 2 files changed, 31 insertions(+)
+
+--- a/drivers/net/phy/phy-c45.c
++++ b/drivers/net/phy/phy-c45.c
+@@ -110,6 +110,36 @@ int genphy_c45_restart_aneg(struct phy_d
+ EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
+ /**
++ * genphy_c45_check_and_restart_aneg - Enable and restart auto-negotiation
++ * @phydev: target phy_device struct
++ * @restart: whether aneg restart is requested
++ *
++ * This assumes that the auto-negotiation MMD is present.
++ *
++ * Check, and restart auto-negotiation if needed.
++ */
++int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
++{
++      int ret = 0;
++
++      if (!restart) {
++              /* Configure and restart aneg if it wasn't set before */
++              ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
++              if (ret < 0)
++                      return ret;
++
++              if (!(ret & MDIO_AN_CTRL1_ENABLE))
++                      restart = true;
++      }
++
++      if (restart)
++              ret = genphy_c45_restart_aneg(phydev);
++
++      return ret;
++}
++EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
++
++/**
+  * genphy_c45_aneg_done - return auto-negotiation complete status
+  * @phydev: target phy_device struct
+  *
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -1098,6 +1098,7 @@ int genphy_write_mmd_unsupported(struct
+ /* Clause 45 PHY */
+ int genphy_c45_restart_aneg(struct phy_device *phydev);
++int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart);
+ int genphy_c45_aneg_done(struct phy_device *phydev);
+ int genphy_c45_read_link(struct phy_device *phydev, u32 mmd_mask);
+ int genphy_c45_read_lpa(struct phy_device *phydev);
diff --git a/target/linux/generic/backport-5.4/708-v5.3-net-phylink-remove-netdev-from-phylink-mii-ioctl-emu.patch b/target/linux/generic/backport-5.4/708-v5.3-net-phylink-remove-netdev-from-phylink-mii-ioctl-emu.patch
new file mode 100644 (file)
index 0000000..1c3f1cc
--- /dev/null
@@ -0,0 +1,59 @@
+From 4c4323084e9a67210c8d269dceba1be99356c414 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 28 May 2019 10:57:18 +0100
+Subject: [PATCH 606/660] net: phylink: remove netdev from phylink mii ioctl
+ emulation
+
+The netdev used in the phylink ioctl emulation is never used, so let's
+remove it.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1360,8 +1360,8 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_set_ee
+  *
+  * FIXME: should deal with negotiation state too.
+  */
+-static int phylink_mii_emul_read(struct net_device *ndev, unsigned int reg,
+-                               struct phylink_link_state *state, bool aneg)
++static int phylink_mii_emul_read(unsigned int reg,
++                               struct phylink_link_state *state)
+ {
+       struct fixed_phy_status fs;
+       int val;
+@@ -1376,8 +1376,6 @@ static int phylink_mii_emul_read(struct
+       if (reg == MII_BMSR) {
+               if (!state->an_complete)
+                       val &= ~BMSR_ANEGCOMPLETE;
+-              if (!aneg)
+-                      val &= ~BMSR_ANEGCAPABLE;
+       }
+       return val;
+ }
+@@ -1473,8 +1471,7 @@ static int phylink_mii_read(struct phyli
+       case MLO_AN_FIXED:
+               if (phy_id == 0) {
+                       phylink_get_fixed_state(pl, &state);
+-                      val = phylink_mii_emul_read(pl->netdev, reg, &state,
+-                                                  true);
++                      val = phylink_mii_emul_read(reg, &state);
+               }
+               break;
+@@ -1487,8 +1484,7 @@ static int phylink_mii_read(struct phyli
+                       if (val < 0)
+                               return val;
+-                      val = phylink_mii_emul_read(pl->netdev, reg, &state,
+-                                                  true);
++                      val = phylink_mii_emul_read(reg, &state);
+               }
+               break;
+       }
diff --git a/target/linux/generic/backport-5.4/709-v5.3-net-phylink-support-for-link-gpio-interrupt.patch b/target/linux/generic/backport-5.4/709-v5.3-net-phylink-support-for-link-gpio-interrupt.patch
new file mode 100644 (file)
index 0000000..84a1c85
--- /dev/null
@@ -0,0 +1,90 @@
+From cba0aba37d2228556e0d1f776d403435868cdbfa Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 28 May 2019 10:57:23 +0100
+Subject: [PATCH 607/660] net: phylink: support for link gpio interrupt
+
+Add support for using GPIO interrupts with a fixed-link GPIO rather than
+polling the GPIO every second and invoking the phylink resolution.  This
+avoids unnecessary calls to mac_config().
+
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 36 ++++++++++++++++++++++++++++++++----
+ 1 file changed, 32 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -59,6 +59,7 @@ struct phylink {
+       phy_interface_t cur_interface;
+       struct gpio_desc *link_gpio;
++      unsigned int link_irq;
+       struct timer_list link_poll;
+       void (*get_fixed_state)(struct net_device *dev,
+                               struct phylink_link_state *s);
+@@ -645,7 +646,7 @@ void phylink_destroy(struct phylink *pl)
+ {
+       if (pl->sfp_bus)
+               sfp_unregister_upstream(pl->sfp_bus);
+-      if (!IS_ERR_OR_NULL(pl->link_gpio))
++      if (pl->link_gpio)
+               gpiod_put(pl->link_gpio);
+       cancel_work_sync(&pl->resolve);
+@@ -912,6 +913,15 @@ void phylink_mac_change(struct phylink *
+ }
+ EXPORT_SYMBOL_GPL(phylink_mac_change);
++static irqreturn_t phylink_link_handler(int irq, void *data)
++{
++      struct phylink *pl = data;
++
++      phylink_run_resolve(pl);
++
++      return IRQ_HANDLED;
++}
++
+ /**
+  * phylink_start() - start a phylink instance
+  * @pl: a pointer to a &struct phylink returned from phylink_create()
+@@ -947,7 +957,22 @@ void phylink_start(struct phylink *pl)
+       clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
+       phylink_run_resolve(pl);
+-      if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
++      if (pl->link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
++              int irq = gpiod_to_irq(pl->link_gpio);
++
++              if (irq > 0) {
++                      if (!request_irq(irq, phylink_link_handler,
++                                       IRQF_TRIGGER_RISING |
++                                       IRQF_TRIGGER_FALLING,
++                                       "netdev link", pl))
++                              pl->link_irq = irq;
++                      else
++                              irq = 0;
++              }
++              if (irq <= 0)
++                      mod_timer(&pl->link_poll, jiffies + HZ);
++      }
++      if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
+               mod_timer(&pl->link_poll, jiffies + HZ);
+       if (pl->sfp_bus)
+               sfp_upstream_start(pl->sfp_bus);
+@@ -973,8 +998,11 @@ void phylink_stop(struct phylink *pl)
+               phy_stop(pl->phydev);
+       if (pl->sfp_bus)
+               sfp_upstream_stop(pl->sfp_bus);
+-      if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
+-              del_timer_sync(&pl->link_poll);
++      del_timer_sync(&pl->link_poll);
++      if (pl->link_irq) {
++              free_irq(pl->link_irq, pl);
++              pl->link_irq = 0;
++      }
+       phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
+ }
diff --git a/target/linux/generic/backport-5.4/710-v5.3-net-phy-allow-Clause-45-access-via-mii-ioctl.patch b/target/linux/generic/backport-5.4/710-v5.3-net-phy-allow-Clause-45-access-via-mii-ioctl.patch
new file mode 100644 (file)
index 0000000..3a601c6
--- /dev/null
@@ -0,0 +1,77 @@
+From eb5df3d026824832831376bbdf04e01a52776eea Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 28 May 2019 10:57:29 +0100
+Subject: [PATCH 608/660] net: phy: allow Clause 45 access via mii ioctl
+
+Allow userspace to generate Clause 45 MII access cycles via phylib.
+This is useful for tools such as mii-diag to be able to inspect Clause
+45 PHYs.
+
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phy.c | 33 ++++++++++++++++++++++++---------
+ 1 file changed, 24 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -397,6 +397,7 @@ int phy_mii_ioctl(struct phy_device *phy
+       struct mii_ioctl_data *mii_data = if_mii(ifr);
+       u16 val = mii_data->val_in;
+       bool change_autoneg = false;
++      int prtad, devad;
+       switch (cmd) {
+       case SIOCGMIIPHY:
+@@ -404,14 +405,29 @@ int phy_mii_ioctl(struct phy_device *phy
+               /* fall through */
+       case SIOCGMIIREG:
+-              mii_data->val_out = mdiobus_read(phydev->mdio.bus,
+-                                               mii_data->phy_id,
+-                                               mii_data->reg_num);
++              if (mdio_phy_id_is_c45(mii_data->phy_id)) {
++                      prtad = mdio_phy_id_prtad(mii_data->phy_id);
++                      devad = mdio_phy_id_devad(mii_data->phy_id);
++                      devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
++              } else {
++                      prtad = mii_data->phy_id;
++                      devad = mii_data->reg_num;
++              }
++              mii_data->val_out = mdiobus_read(phydev->mdio.bus, prtad,
++                                               devad);
+               return 0;
+       case SIOCSMIIREG:
+-              if (mii_data->phy_id == phydev->mdio.addr) {
+-                      switch (mii_data->reg_num) {
++              if (mdio_phy_id_is_c45(mii_data->phy_id)) {
++                      prtad = mdio_phy_id_prtad(mii_data->phy_id);
++                      devad = mdio_phy_id_devad(mii_data->phy_id);
++                      devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
++              } else {
++                      prtad = mii_data->phy_id;
++                      devad = mii_data->reg_num;
++              }
++              if (prtad == phydev->mdio.addr) {
++                      switch (devad) {
+                       case MII_BMCR:
+                               if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) {
+                                       if (phydev->autoneg == AUTONEG_ENABLE)
+@@ -443,11 +459,10 @@ int phy_mii_ioctl(struct phy_device *phy
+                       }
+               }
+-              mdiobus_write(phydev->mdio.bus, mii_data->phy_id,
+-                            mii_data->reg_num, val);
++              mdiobus_write(phydev->mdio.bus, prtad, devad, val);
+-              if (mii_data->phy_id == phydev->mdio.addr &&
+-                  mii_data->reg_num == MII_BMCR &&
++              if (prtad == phydev->mdio.addr &&
++                  devad == MII_BMCR &&
+                   val & BMCR_RESET)
+                       return phy_init_hw(phydev);
diff --git a/target/linux/generic/backport-5.4/711-v5.3-net-sfp-add-mandatory-attach-detach-methods-for-sfp-.patch b/target/linux/generic/backport-5.4/711-v5.3-net-sfp-add-mandatory-attach-detach-methods-for-sfp-.patch
new file mode 100644 (file)
index 0000000..74dc39f
--- /dev/null
@@ -0,0 +1,94 @@
+From aeabfaa63285470e81fa341e14f92d68880aa160 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 28 May 2019 10:57:34 +0100
+Subject: [PATCH 609/660] net: sfp: add mandatory attach/detach methods for sfp
+ buses
+
+Add attach and detach methods for SFP buses, which will allow us to get
+rid of the netdev storage in sfp-bus.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 16 ++++++++++++++++
+ drivers/net/phy/sfp-bus.c |  4 ++--
+ include/linux/sfp.h       |  6 ++++++
+ 3 files changed, 24 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1615,6 +1615,20 @@ int phylink_mii_ioctl(struct phylink *pl
+ }
+ EXPORT_SYMBOL_GPL(phylink_mii_ioctl);
++static void phylink_sfp_attach(void *upstream, struct sfp_bus *bus)
++{
++      struct phylink *pl = upstream;
++
++      pl->netdev->sfp_bus = bus;
++}
++
++static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus)
++{
++      struct phylink *pl = upstream;
++
++      pl->netdev->sfp_bus = NULL;
++}
++
+ static int phylink_sfp_module_insert(void *upstream,
+                                    const struct sfp_eeprom_id *id)
+ {
+@@ -1733,6 +1747,8 @@ static void phylink_sfp_disconnect_phy(v
+ }
+ static const struct sfp_upstream_ops sfp_phylink_ops = {
++      .attach = phylink_sfp_attach,
++      .detach = phylink_sfp_detach,
+       .module_insert = phylink_sfp_module_insert,
+       .link_up = phylink_sfp_link_up,
+       .link_down = phylink_sfp_link_down,
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -350,7 +350,7 @@ static int sfp_register_bus(struct sfp_b
+       bus->socket_ops->attach(bus->sfp);
+       if (bus->started)
+               bus->socket_ops->start(bus->sfp);
+-      bus->netdev->sfp_bus = bus;
++      bus->upstream_ops->attach(bus->upstream, bus);
+       bus->registered = true;
+       return 0;
+ }
+@@ -359,8 +359,8 @@ static void sfp_unregister_bus(struct sf
+ {
+       const struct sfp_upstream_ops *ops = bus->upstream_ops;
+-      bus->netdev->sfp_bus = NULL;
+       if (bus->registered) {
++              bus->upstream_ops->detach(bus->upstream, bus);
+               if (bus->started)
+                       bus->socket_ops->stop(bus->sfp);
+               bus->socket_ops->detach(bus->sfp);
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -469,6 +469,10 @@ struct sfp_bus;
+ /**
+  * struct sfp_upstream_ops - upstream operations structure
++ * @attach: called when the sfp socket driver is bound to the upstream
++ *   (mandatory).
++ * @detach: called when the sfp socket driver is unbound from the upstream
++ *   (mandatory).
+  * @module_insert: called after a module has been detected to determine
+  *   whether the module is supported for the upstream device.
+  * @module_remove: called after the module has been removed.
+@@ -481,6 +485,8 @@ struct sfp_bus;
+  *   been removed.
+  */
+ struct sfp_upstream_ops {
++      void (*attach)(void *priv, struct sfp_bus *bus);
++      void (*detach)(void *priv, struct sfp_bus *bus);
+       int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
+       void (*module_remove)(void *priv);
+       void (*link_down)(void *priv);
diff --git a/target/linux/generic/backport-5.4/712-v5.3-net-sfp-remove-sfp-bus-use-of-netdevs.patch b/target/linux/generic/backport-5.4/712-v5.3-net-sfp-remove-sfp-bus-use-of-netdevs.patch
new file mode 100644 (file)
index 0000000..8f0c37e
--- /dev/null
@@ -0,0 +1,118 @@
+From 60d756717d772be90d07a07cd2cc140c76da3e4a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 28 May 2019 10:57:39 +0100
+Subject: [PATCH 610/660] net: sfp: remove sfp-bus use of netdevs
+
+The sfp-bus code now no longer has any use for the network device
+structure, so remove its use.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c |  3 +--
+ drivers/net/phy/sfp-bus.c | 10 +++-------
+ include/linux/sfp.h       |  6 ++----
+ 3 files changed, 6 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -555,8 +555,7 @@ static int phylink_register_sfp(struct p
+               return ret;
+       }
+-      pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl->netdev, pl,
+-                                          &sfp_phylink_ops);
++      pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops);
+       if (!pl->sfp_bus)
+               return -ENOMEM;
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -23,7 +23,6 @@ struct sfp_bus {
+       const struct sfp_upstream_ops *upstream_ops;
+       void *upstream;
+-      struct net_device *netdev;
+       struct phy_device *phydev;
+       bool registered;
+@@ -442,13 +441,11 @@ static void sfp_upstream_clear(struct sf
+ {
+       bus->upstream_ops = NULL;
+       bus->upstream = NULL;
+-      bus->netdev = NULL;
+ }
+ /**
+  * sfp_register_upstream() - Register the neighbouring device
+  * @fwnode: firmware node for the SFP bus
+- * @ndev: network device associated with the interface
+  * @upstream: the upstream private data
+  * @ops: the upstream's &struct sfp_upstream_ops
+  *
+@@ -459,7 +456,7 @@ static void sfp_upstream_clear(struct sf
+  * On error, returns %NULL.
+  */
+ struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
+-                                    struct net_device *ndev, void *upstream,
++                                    void *upstream,
+                                     const struct sfp_upstream_ops *ops)
+ {
+       struct sfp_bus *bus = sfp_bus_get(fwnode);
+@@ -469,7 +466,6 @@ struct sfp_bus *sfp_register_upstream(st
+               rtnl_lock();
+               bus->upstream_ops = ops;
+               bus->upstream = upstream;
+-              bus->netdev = ndev;
+               if (bus->sfp) {
+                       ret = sfp_register_bus(bus);
+@@ -591,7 +587,7 @@ struct sfp_bus *sfp_register_socket(stru
+               bus->sfp = sfp;
+               bus->socket_ops = ops;
+-              if (bus->netdev) {
++              if (bus->upstream_ops) {
+                       ret = sfp_register_bus(bus);
+                       if (ret)
+                               sfp_socket_clear(bus);
+@@ -611,7 +607,7 @@ EXPORT_SYMBOL_GPL(sfp_register_socket);
+ void sfp_unregister_socket(struct sfp_bus *bus)
+ {
+       rtnl_lock();
+-      if (bus->netdev)
++      if (bus->upstream_ops)
+               sfp_unregister_bus(bus);
+       sfp_socket_clear(bus);
+       rtnl_unlock();
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -464,7 +464,6 @@ enum {
+ struct fwnode_handle;
+ struct ethtool_eeprom;
+ struct ethtool_modinfo;
+-struct net_device;
+ struct sfp_bus;
+ /**
+@@ -510,7 +509,7 @@ int sfp_get_module_eeprom(struct sfp_bus
+ void sfp_upstream_start(struct sfp_bus *bus);
+ void sfp_upstream_stop(struct sfp_bus *bus);
+ struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
+-                                    struct net_device *ndev, void *upstream,
++                                    void *upstream,
+                                     const struct sfp_upstream_ops *ops);
+ void sfp_unregister_upstream(struct sfp_bus *bus);
+ #else
+@@ -555,8 +554,7 @@ static inline void sfp_upstream_stop(str
+ }
+ static inline struct sfp_bus *sfp_register_upstream(
+-      struct fwnode_handle *fwnode,
+-      struct net_device *ndev, void *upstream,
++      struct fwnode_handle *fwnode, void *upstream,
+       const struct sfp_upstream_ops *ops)
+ {
+       return (struct sfp_bus *)-1;
diff --git a/target/linux/generic/backport-5.4/713-v5.2-net-phylink-avoid-reducing-support-mask.patch b/target/linux/generic/backport-5.4/713-v5.2-net-phylink-avoid-reducing-support-mask.patch
new file mode 100644 (file)
index 0000000..3aa8d9e
--- /dev/null
@@ -0,0 +1,84 @@
+From 8ac1d3e5cf7d277769ba3403d99f643fab1e3fae Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sat, 23 Nov 2019 14:19:54 +0000
+Subject: [PATCH 611/660] net: phylink: avoid reducing support mask
+
+Avoid reducing the support mask as a result of the interface type
+selected for SFP modules, or when setting the link settings through
+ethtool - this should only change when the supported link modes of
+the hardware combination change.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phylink.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -1137,6 +1137,7 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_ksetti
+ int phylink_ethtool_ksettings_set(struct phylink *pl,
+                                 const struct ethtool_link_ksettings *kset)
+ {
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
+       struct ethtool_link_ksettings our_kset;
+       struct phylink_link_state config;
+       int ret;
+@@ -1147,11 +1148,12 @@ int phylink_ethtool_ksettings_set(struct
+           kset->base.autoneg != AUTONEG_ENABLE)
+               return -EINVAL;
++      linkmode_copy(support, pl->supported);
+       config = pl->link_config;
+       /* Mask out unsupported advertisements */
+       linkmode_and(config.advertising, kset->link_modes.advertising,
+-                   pl->supported);
++                   support);
+       /* FIXME: should we reject autoneg if phy/mac does not support it? */
+       if (kset->base.autoneg == AUTONEG_DISABLE) {
+@@ -1161,7 +1163,7 @@ int phylink_ethtool_ksettings_set(struct
+                * duplex.
+                */
+               s = phy_lookup_setting(kset->base.speed, kset->base.duplex,
+-                                     pl->supported,
++                                     support,
+                                      __ETHTOOL_LINK_MODE_MASK_NBITS, false);
+               if (!s)
+                       return -EINVAL;
+@@ -1191,7 +1193,7 @@ int phylink_ethtool_ksettings_set(struct
+               __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising);
+       }
+-      if (phylink_validate(pl, pl->supported, &config))
++      if (phylink_validate(pl, support, &config))
+               return -EINVAL;
+       /* If autonegotiation is enabled, we must have an advertisement */
+@@ -1633,6 +1635,7 @@ static int phylink_sfp_module_insert(voi
+ {
+       struct phylink *pl = upstream;
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
++      __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
+       struct phylink_link_state config;
+       phy_interface_t iface;
+       int ret = 0;
+@@ -1660,6 +1663,8 @@ static int phylink_sfp_module_insert(voi
+               return ret;
+       }
++      linkmode_copy(support1, support);
++
+       iface = sfp_select_interface(pl->sfp_bus, id, config.advertising);
+       if (iface == PHY_INTERFACE_MODE_NA) {
+               netdev_err(pl->netdev,
+@@ -1669,7 +1674,7 @@ static int phylink_sfp_module_insert(voi
+       }
+       config.interface = iface;
+-      ret = phylink_validate(pl, support, &config);
++      ret = phylink_validate(pl, support1, &config);
+       if (ret) {
+               netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n",
+                          phylink_an_mode_str(MLO_AN_INBAND),
diff --git a/target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch b/target/linux/generic/backport-5.4/714-v5.3-net-sfp-Stop-SFP-polling-and-interrupt-handling-duri.patch
new file mode 100644 (file)
index 0000000..0509950
--- /dev/null
@@ -0,0 +1,94 @@
+From 254236a22109efa84c9e9f5a9c76a1719439e309 Mon Sep 17 00:00:00 2001
+From: Robert Hancock <hancock@sedsystems.ca>
+Date: Fri, 7 Jun 2019 10:42:35 -0600
+Subject: [PATCH 612/660] net: sfp: Stop SFP polling and interrupt handling
+ during shutdown
+
+SFP device polling can cause problems during the shutdown process if the
+parent devices of the network controller have been shut down already.
+This problem was seen on the iMX6 platform with PCIe devices, where
+accessing the device after the bus is shut down causes a hang.
+
+Free any acquired GPIO interrupts and stop all delayed work in the SFP
+driver during the shutdown process, so that we ensure that no pending
+operations are still occurring after the SFP shutdown completes.
+
+Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/sfp.c | 31 ++++++++++++++++++++++++++-----
+ 1 file changed, 26 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -183,6 +183,7 @@ struct sfp {
+       int (*write)(struct sfp *, bool, u8, void *, size_t);
+       struct gpio_desc *gpio[GPIO_MAX];
++      int gpio_irq[GPIO_MAX];
+       bool attached;
+       struct mutex st_mutex;                  /* Protects state */
+@@ -1803,7 +1804,7 @@ static int sfp_probe(struct platform_dev
+       const struct sff_data *sff;
+       struct sfp *sfp;
+       bool poll = false;
+-      int irq, err, i;
++      int err, i;
+       sfp = sfp_alloc(&pdev->dev);
+       if (IS_ERR(sfp))
+@@ -1885,19 +1886,22 @@ static int sfp_probe(struct platform_dev
+               if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
+                       continue;
+-              irq = gpiod_to_irq(sfp->gpio[i]);
+-              if (!irq) {
++              sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
++              if (!sfp->gpio_irq[i]) {
+                       poll = true;
+                       continue;
+               }
+-              err = devm_request_threaded_irq(sfp->dev, irq, NULL, sfp_irq,
++              err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i],
++                                              NULL, sfp_irq,
+                                               IRQF_ONESHOT |
+                                               IRQF_TRIGGER_RISING |
+                                               IRQF_TRIGGER_FALLING,
+                                               dev_name(sfp->dev), sfp);
+-              if (err)
++              if (err) {
++                      sfp->gpio_irq[i] = 0;
+                       poll = true;
++              }
+       }
+       if (poll)
+@@ -1928,9 +1932,26 @@ static int sfp_remove(struct platform_de
+       return 0;
+ }
++static void sfp_shutdown(struct platform_device *pdev)
++{
++      struct sfp *sfp = platform_get_drvdata(pdev);
++      int i;
++
++      for (i = 0; i < GPIO_MAX; i++) {
++              if (!sfp->gpio_irq[i])
++                      continue;
++
++              devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp);
++      }
++
++      cancel_delayed_work_sync(&sfp->poll);
++      cancel_delayed_work_sync(&sfp->timeout);
++}
++
+ static struct platform_driver sfp_driver = {
+       .probe = sfp_probe,
+       .remove = sfp_remove,
++      .shutdown = sfp_shutdown,
+       .driver = {
+               .name = "sfp",
+               .of_match_table = sfp_of_match,
diff --git a/target/linux/generic/backport-5.4/715-v5.3-net-phylink-don-t-start-and-stop-SGMII-PHYs-in-SFP-m.patch b/target/linux/generic/backport-5.4/715-v5.3-net-phylink-don-t-start-and-stop-SGMII-PHYs-in-SFP-m.patch
new file mode 100644 (file)
index 0000000..94fb2fb
--- /dev/null
@@ -0,0 +1,141 @@
+From b8803113537a1c1f457eba6270d46e3af305031f Mon Sep 17 00:00:00 2001
+From: Arseny Solokha <asolokha@kb.kras.ru>
+Date: Wed, 24 Jul 2019 20:31:39 +0700
+Subject: [PATCH 613/660] net: phylink: don't start and stop SGMII PHYs in SFP
+ modules twice
+
+SFP modules connected using the SGMII interface have their own PHYs which
+are handled by the struct phylink's phydev field. On the other hand, for
+the modules connected using 1000Base-X interface that field is not set.
+
+Since commit ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network
+devices and sfp cages") phylink_start() ends up setting the phydev field
+using the sfp-bus infrastructure, which eventually calls phy_start() on it,
+and then calling phy_start() again on the same phydev from phylink_start()
+itself. Similar call sequence holds for phylink_stop(), only in the reverse
+order. This results in WARNs during network interface bringup and shutdown
+when a copper SFP module is connected, as phy_start() and phy_stop() are
+called twice in a row for the same phy_device:
+
+  % ip link set up dev eth0
+  ------------[ cut here ]------------
+  called from state UP
+  WARNING: CPU: 1 PID: 155 at drivers/net/phy/phy.c:895 phy_start+0x74/0xc0
+  Modules linked in:
+  CPU: 1 PID: 155 Comm: backend Not tainted 5.2.0+ #1
+  NIP:  c0227bf0 LR: c0227bf0 CTR: c004d224
+  REGS: df547720 TRAP: 0700   Not tainted  (5.2.0+)
+  MSR:  00029000 <CE,EE,ME>  CR: 24002822  XER: 00000000
+
+  GPR00: c0227bf0 df5477d8 df5d7080 00000014 df9d2370 df9d5ac4 1f4eb000 00000001
+  GPR08: c061fe58 00000000 00000000 df5477d8 0000003c 100c8768 00000000 00000000
+  GPR16: df486a00 c046f1c8 c046eea0 00000000 c046e904 c0239604 db68449c 00000000
+  GPR24: e9083204 00000000 00000001 db684460 e9083404 00000000 db6dce00 db6dcc00
+  NIP [c0227bf0] phy_start+0x74/0xc0
+  LR [c0227bf0] phy_start+0x74/0xc0
+  Call Trace:
+  [df5477d8] [c0227bf0] phy_start+0x74/0xc0 (unreliable)
+  [df5477e8] [c023cad0] startup_gfar+0x398/0x3f4
+  [df547828] [c023cf08] gfar_enet_open+0x364/0x374
+  [df547898] [c029d870] __dev_open+0xe4/0x140
+  [df5478c8] [c029db70] __dev_change_flags+0xf0/0x188
+  [df5478f8] [c029dc28] dev_change_flags+0x20/0x54
+  [df547918] [c02ae304] do_setlink+0x310/0x818
+  [df547a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0
+  [df547c28] [c02b222c] rtnl_newlink+0x48/0x68
+  [df547c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c
+  [df547c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0
+  [df547cd8] [c02cba3c] netlink_unicast+0x114/0x19c
+  [df547d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0
+  [df547d58] [c027b668] sock_sendmsg_nosec+0x20/0x40
+  [df547d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc
+  [df547e98] [c027df7c] __sys_sendmsg+0x68/0x84
+  [df547ef8] [c027e430] sys_socketcall+0x1a0/0x204
+  [df547f38] [c000d1d8] ret_from_syscall+0x0/0x38
+  --- interrupt: c01 at 0xfd4e030
+      LR = 0xfd4e010
+  Instruction dump:
+  813f0188 38800000 2b890005 419d0014 3d40c046 5529103a 394aa208 7c8a482e
+  3c60c046 3863a1b8 4cc63182 4be009a1 <0fe00000> 48000030 3c60c046 3863a1d0
+  ---[ end trace d4c095aeaf6ea998 ]---
+
+and
+
+  % ip link set down dev eth0
+  ------------[ cut here ]------------
+  called from state HALTED
+  WARNING: CPU: 1 PID: 184 at drivers/net/phy/phy.c:858 phy_stop+0x3c/0x88
+
+  <...>
+
+  Call Trace:
+  [df581788] [c0228450] phy_stop+0x3c/0x88 (unreliable)
+  [df581798] [c022d548] sfp_sm_phy_detach+0x1c/0x44
+  [df5817a8] [c022e8cc] sfp_sm_event+0x4b0/0x87c
+  [df581848] [c022f04c] sfp_upstream_stop+0x34/0x44
+  [df581858] [c0225608] phylink_stop+0x7c/0xe4
+  [df581868] [c023c57c] stop_gfar+0x7c/0x94
+  [df581888] [c023c5b8] gfar_close+0x24/0x94
+  [df5818a8] [c0298688] __dev_close_many+0xdc/0xf8
+  [df5818c8] [c029db58] __dev_change_flags+0xd8/0x188
+  [df5818f8] [c029dc28] dev_change_flags+0x20/0x54
+  [df581918] [c02ae304] do_setlink+0x310/0x818
+  [df581a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0
+  [df581c28] [c02b222c] rtnl_newlink+0x48/0x68
+  [df581c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c
+  [df581c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0
+  [df581cd8] [c02cba3c] netlink_unicast+0x114/0x19c
+  [df581d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0
+  [df581d58] [c027b668] sock_sendmsg_nosec+0x20/0x40
+  [df581d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc
+  [df581e98] [c027df7c] __sys_sendmsg+0x68/0x84
+  [df581ef8] [c027e430] sys_socketcall+0x1a0/0x204
+  [df581f38] [c000d1d8] ret_from_syscall+0x0/0x38
+
+  <...>
+
+  ---[ end trace d4c095aeaf6ea999 ]---
+
+SFP modules with the 1000Base-X interface are not affected.
+
+Place explicit calls to phy_start() and phy_stop() before enabling or after
+disabling an attached SFP module, where phydev is not yet set (or is
+already unset), so they will be made only from the inside of sfp-bus, if
+needed.
+
+Fixes: 217962615662 ("net: phy: warn if phy_start is called from invalid state")
+Signed-off-by: Arseny Solokha <asolokha@kb.kras.ru>
+Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phylink.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -973,10 +973,10 @@ void phylink_start(struct phylink *pl)
+       }
+       if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
+               mod_timer(&pl->link_poll, jiffies + HZ);
+-      if (pl->sfp_bus)
+-              sfp_upstream_start(pl->sfp_bus);
+       if (pl->phydev)
+               phy_start(pl->phydev);
++      if (pl->sfp_bus)
++              sfp_upstream_start(pl->sfp_bus);
+ }
+ EXPORT_SYMBOL_GPL(phylink_start);
+@@ -993,10 +993,10 @@ void phylink_stop(struct phylink *pl)
+ {
+       ASSERT_RTNL();
+-      if (pl->phydev)
+-              phy_stop(pl->phydev);
+       if (pl->sfp_bus)
+               sfp_upstream_stop(pl->sfp_bus);
++      if (pl->phydev)
++              phy_stop(pl->phydev);
+       del_timer_sync(&pl->link_poll);
+       if (pl->link_irq) {
+               free_irq(pl->link_irq, pl);
diff --git a/target/linux/generic/backport-5.4/716-v5.4-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch b/target/linux/generic/backport-5.4/716-v5.4-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch
new file mode 100644 (file)
index 0000000..27ab78f
--- /dev/null
@@ -0,0 +1,179 @@
+From 4054955f0da08c81d42220cb445820d474f1ac92 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sat, 14 Sep 2019 14:21:22 +0100
+Subject: [PATCH 614/660] net: sfp: move fwnode parsing into sfp-bus layer
+
+Rather than parsing the sfp firmware node in phylink, parse it in the
+sfp-bus code, so we can re-use this code for PHYs without having to
+duplicate the parsing.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 21 ++++---------
+ drivers/net/phy/sfp-bus.c | 65 +++++++++++++++++++++++++--------------
+ include/linux/sfp.h       | 10 +++---
+ 3 files changed, 53 insertions(+), 43 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -538,26 +538,17 @@ static const struct sfp_upstream_ops sfp
+ static int phylink_register_sfp(struct phylink *pl,
+                               struct fwnode_handle *fwnode)
+ {
+-      struct fwnode_reference_args ref;
++      struct sfp_bus *bus;
+       int ret;
+-      if (!fwnode)
+-              return 0;
+-
+-      ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL,
+-                                               0, 0, &ref);
+-      if (ret < 0) {
+-              if (ret == -ENOENT)
+-                      return 0;
+-
+-              netdev_err(pl->netdev, "unable to parse \"sfp\" node: %d\n",
+-                         ret);
++      bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops);
++      if (IS_ERR(bus)) {
++              ret = PTR_ERR(bus);
++              netdev_err(pl->netdev, "unable to attach SFP bus: %d\n", ret);
+               return ret;
+       }
+-      pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops);
+-      if (!pl->sfp_bus)
+-              return -ENOMEM;
++      pl->sfp_bus = bus;
+       return 0;
+ }
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -3,6 +3,7 @@
+ #include <linux/list.h>
+ #include <linux/mutex.h>
+ #include <linux/phylink.h>
++#include <linux/property.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/slab.h>
+@@ -444,45 +445,63 @@ static void sfp_upstream_clear(struct sf
+ }
+ /**
+- * sfp_register_upstream() - Register the neighbouring device
+- * @fwnode: firmware node for the SFP bus
++ * sfp_register_upstream_node() - parse and register the neighbouring device
++ * @fwnode: firmware node for the parent device (MAC or PHY)
+  * @upstream: the upstream private data
+  * @ops: the upstream's &struct sfp_upstream_ops
+  *
+- * Register the upstream device (eg, PHY) with the SFP bus. MAC drivers
+- * should use phylink, which will call this function for them. Returns
+- * a pointer to the allocated &struct sfp_bus.
++ * Parse the parent device's firmware node for a SFP bus, and register the
++ * SFP bus using sfp_register_upstream().
+  *
+- * On error, returns %NULL.
++ * Returns: on success, a pointer to the sfp_bus structure,
++ *        %NULL if no SFP is specified,
++ *        on failure, an error pointer value:
++ *            corresponding to the errors detailed for
++ *            fwnode_property_get_reference_args().
++ *            %-ENOMEM if we failed to allocate the bus.
++ *            an error from the upstream's connect_phy() method.
+  */
+-struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
+-                                    void *upstream,
+-                                    const struct sfp_upstream_ops *ops)
+-{
+-      struct sfp_bus *bus = sfp_bus_get(fwnode);
+-      int ret = 0;
+-
+-      if (bus) {
+-              rtnl_lock();
+-              bus->upstream_ops = ops;
+-              bus->upstream = upstream;
++struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
++                                         void *upstream,
++                                         const struct sfp_upstream_ops *ops)
++{
++      struct fwnode_reference_args ref;
++      struct sfp_bus *bus;
++      int ret;
+-              if (bus->sfp) {
+-                      ret = sfp_register_bus(bus);
+-                      if (ret)
+-                              sfp_upstream_clear(bus);
+-              }
+-              rtnl_unlock();
++      ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL,
++                                               0, 0, &ref);
++      if (ret == -ENOENT)
++              return NULL;
++      else if (ret < 0)
++              return ERR_PTR(ret);
++
++      bus = sfp_bus_get(ref.fwnode);
++      fwnode_handle_put(ref.fwnode);
++      if (!bus)
++              return ERR_PTR(-ENOMEM);
++
++      rtnl_lock();
++      bus->upstream_ops = ops;
++      bus->upstream = upstream;
++
++      if (bus->sfp) {
++              ret = sfp_register_bus(bus);
++              if (ret)
++                      sfp_upstream_clear(bus);
++      } else {
++              ret = 0;
+       }
++      rtnl_unlock();
+       if (ret) {
+               sfp_bus_put(bus);
+-              bus = NULL;
++              bus = ERR_PTR(ret);
+       }
+       return bus;
+ }
+-EXPORT_SYMBOL_GPL(sfp_register_upstream);
++EXPORT_SYMBOL_GPL(sfp_register_upstream_node);
+ /**
+  * sfp_unregister_upstream() - Unregister sfp bus
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -508,9 +508,9 @@ int sfp_get_module_eeprom(struct sfp_bus
+                         u8 *data);
+ void sfp_upstream_start(struct sfp_bus *bus);
+ void sfp_upstream_stop(struct sfp_bus *bus);
+-struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
+-                                    void *upstream,
+-                                    const struct sfp_upstream_ops *ops);
++struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
++                                         void *upstream,
++                                         const struct sfp_upstream_ops *ops);
+ void sfp_unregister_upstream(struct sfp_bus *bus);
+ #else
+ static inline int sfp_parse_port(struct sfp_bus *bus,
+@@ -553,11 +553,11 @@ static inline void sfp_upstream_stop(str
+ {
+ }
+-static inline struct sfp_bus *sfp_register_upstream(
++static inline struct sfp_bus *sfp_register_upstream_node(
+       struct fwnode_handle *fwnode, void *upstream,
+       const struct sfp_upstream_ops *ops)
+ {
+-      return (struct sfp_bus *)-1;
++      return NULL;
+ }
+ static inline void sfp_unregister_upstream(struct sfp_bus *bus)
diff --git a/target/linux/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch b/target/linux/generic/backport-5.4/717-v5.5-net-sfp-rework-upstream-interface.patch
new file mode 100644 (file)
index 0000000..f7dd187
--- /dev/null
@@ -0,0 +1,254 @@
+From 863b5b6941f9f43b924393b6ba2b36647e7dee42 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 7 Nov 2019 17:06:08 +0000
+Subject: [PATCH 615/660] net: sfp: rework upstream interface
+
+The current upstream interface is an all-or-nothing, which is
+sub-optimal for future changes, as it doesn't allow the upstream driver
+to prepare for the SFP module becoming available, as it is at boot.
+
+Switch to a find-sfp-bus, add-upstream, del-upstream, put-sfp-bus
+interface structure instead, which allows the upstream driver to
+prepare for a module being available as soon as add-upstream is called.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/phylink.c | 10 +++--
+ drivers/net/phy/sfp-bus.c | 92 +++++++++++++++++++++++++++------------
+ include/linux/sfp.h       | 25 +++++++----
+ 3 files changed, 88 insertions(+), 39 deletions(-)
+
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -541,7 +541,7 @@ static int phylink_register_sfp(struct p
+       struct sfp_bus *bus;
+       int ret;
+-      bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops);
++      bus = sfp_bus_find_fwnode(fwnode);
+       if (IS_ERR(bus)) {
+               ret = PTR_ERR(bus);
+               netdev_err(pl->netdev, "unable to attach SFP bus: %d\n", ret);
+@@ -550,7 +550,10 @@ static int phylink_register_sfp(struct p
+       pl->sfp_bus = bus;
+-      return 0;
++      ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops);
++      sfp_bus_put(bus);
++
++      return ret;
+ }
+ /**
+@@ -634,8 +637,7 @@ EXPORT_SYMBOL_GPL(phylink_create);
+  */
+ void phylink_destroy(struct phylink *pl)
+ {
+-      if (pl->sfp_bus)
+-              sfp_unregister_upstream(pl->sfp_bus);
++      sfp_bus_del_upstream(pl->sfp_bus);
+       if (pl->link_gpio)
+               gpiod_put(pl->link_gpio);
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -328,10 +328,19 @@ static void sfp_bus_release(struct kref
+       kfree(bus);
+ }
+-static void sfp_bus_put(struct sfp_bus *bus)
++/**
++ * sfp_bus_put() - put a reference on the &struct sfp_bus
++ * bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ *
++ * Put a reference on the &struct sfp_bus and free the underlying structure
++ * if this was the last reference.
++ */
++void sfp_bus_put(struct sfp_bus *bus)
+ {
+-      kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
++      if (bus)
++              kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
+ }
++EXPORT_SYMBOL_GPL(sfp_bus_put);
+ static int sfp_register_bus(struct sfp_bus *bus)
+ {
+@@ -347,11 +356,11 @@ static int sfp_register_bus(struct sfp_b
+                               return ret;
+               }
+       }
++      bus->registered = true;
+       bus->socket_ops->attach(bus->sfp);
+       if (bus->started)
+               bus->socket_ops->start(bus->sfp);
+       bus->upstream_ops->attach(bus->upstream, bus);
+-      bus->registered = true;
+       return 0;
+ }
+@@ -445,13 +454,12 @@ static void sfp_upstream_clear(struct sf
+ }
+ /**
+- * sfp_register_upstream_node() - parse and register the neighbouring device
++ * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode
+  * @fwnode: firmware node for the parent device (MAC or PHY)
+- * @upstream: the upstream private data
+- * @ops: the upstream's &struct sfp_upstream_ops
+  *
+- * Parse the parent device's firmware node for a SFP bus, and register the
+- * SFP bus using sfp_register_upstream().
++ * Parse the parent device's firmware node for a SFP bus, and locate
++ * the sfp_bus structure, incrementing its reference count.  This must
++ * be put via sfp_bus_put() when done.
+  *
+  * Returns: on success, a pointer to the sfp_bus structure,
+  *        %NULL if no SFP is specified,
+@@ -461,9 +469,7 @@ static void sfp_upstream_clear(struct sf
+  *            %-ENOMEM if we failed to allocate the bus.
+  *            an error from the upstream's connect_phy() method.
+  */
+-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
+-                                         void *upstream,
+-                                         const struct sfp_upstream_ops *ops)
++struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
+ {
+       struct fwnode_reference_args ref;
+       struct sfp_bus *bus;
+@@ -481,7 +487,39 @@ struct sfp_bus *sfp_register_upstream_no
+       if (!bus)
+               return ERR_PTR(-ENOMEM);
++      return bus;
++}
++EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode);
++
++/**
++ * sfp_bus_add_upstream() - parse and register the neighbouring device
++ * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ * @upstream: the upstream private data
++ * @ops: the upstream's &struct sfp_upstream_ops
++ *
++ * Add upstream driver for the SFP bus, and if the bus is complete, register
++ * the SFP bus using sfp_register_upstream().  This takes a reference on the
++ * bus, so it is safe to put the bus after this call.
++ *
++ * Returns: on success, a pointer to the sfp_bus structure,
++ *        %NULL if no SFP is specified,
++ *        on failure, an error pointer value:
++ *            corresponding to the errors detailed for
++ *            fwnode_property_get_reference_args().
++ *            %-ENOMEM if we failed to allocate the bus.
++ *            an error from the upstream's connect_phy() method.
++ */
++int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++                       const struct sfp_upstream_ops *ops)
++{
++      int ret;
++
++      /* If no bus, return success */
++      if (!bus)
++              return 0;
++
+       rtnl_lock();
++      kref_get(&bus->kref);
+       bus->upstream_ops = ops;
+       bus->upstream = upstream;
+@@ -494,33 +532,33 @@ struct sfp_bus *sfp_register_upstream_no
+       }
+       rtnl_unlock();
+-      if (ret) {
++      if (ret)
+               sfp_bus_put(bus);
+-              bus = ERR_PTR(ret);
+-      }
+-      return bus;
++      return ret;
+ }
+-EXPORT_SYMBOL_GPL(sfp_register_upstream_node);
++EXPORT_SYMBOL_GPL(sfp_bus_add_upstream);
+ /**
+- * sfp_unregister_upstream() - Unregister sfp bus
++ * sfp_bus_del_upstream() - Delete a sfp bus
+  * @bus: a pointer to the &struct sfp_bus structure for the sfp module
+  *
+- * Unregister a previously registered upstream connection for the SFP
+- * module. @bus is returned from sfp_register_upstream().
++ * Delete a previously registered upstream connection for the SFP
++ * module. @bus should have been added by sfp_bus_add_upstream().
+  */
+-void sfp_unregister_upstream(struct sfp_bus *bus)
++void sfp_bus_del_upstream(struct sfp_bus *bus)
+ {
+-      rtnl_lock();
+-      if (bus->sfp)
+-              sfp_unregister_bus(bus);
+-      sfp_upstream_clear(bus);
+-      rtnl_unlock();
++      if (bus) {
++              rtnl_lock();
++              if (bus->sfp)
++                      sfp_unregister_bus(bus);
++              sfp_upstream_clear(bus);
++              rtnl_unlock();
+-      sfp_bus_put(bus);
++              sfp_bus_put(bus);
++      }
+ }
+-EXPORT_SYMBOL_GPL(sfp_unregister_upstream);
++EXPORT_SYMBOL_GPL(sfp_bus_del_upstream);
+ /* Socket driver entry points */
+ int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -508,10 +508,11 @@ int sfp_get_module_eeprom(struct sfp_bus
+                         u8 *data);
+ void sfp_upstream_start(struct sfp_bus *bus);
+ void sfp_upstream_stop(struct sfp_bus *bus);
+-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
+-                                         void *upstream,
+-                                         const struct sfp_upstream_ops *ops);
+-void sfp_unregister_upstream(struct sfp_bus *bus);
++void sfp_bus_put(struct sfp_bus *bus);
++struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode);
++int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++                       const struct sfp_upstream_ops *ops);
++void sfp_bus_del_upstream(struct sfp_bus *bus);
+ #else
+ static inline int sfp_parse_port(struct sfp_bus *bus,
+                                const struct sfp_eeprom_id *id,
+@@ -553,14 +554,22 @@ static inline void sfp_upstream_stop(str
+ {
+ }
+-static inline struct sfp_bus *sfp_register_upstream_node(
+-      struct fwnode_handle *fwnode, void *upstream,
+-      const struct sfp_upstream_ops *ops)
++static inline void sfp_bus_put(struct sfp_bus *bus)
++{
++}
++
++static inline struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
+ {
+       return NULL;
+ }
+-static inline void sfp_unregister_upstream(struct sfp_bus *bus)
++static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++                              const struct sfp_upstream_ops *ops)
++{
++      return 0;
++}
++
++static inline void sfp_bus_del_upstream(struct sfp_bus *bus)
+ {
+ }
+ #endif
diff --git a/target/linux/generic/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch b/target/linux/generic/backport-5.4/718-v5.5-net-sfp-fix-sfp_bus_put-kernel-documentation.patch
new file mode 100644 (file)
index 0000000..59d2ce5
--- /dev/null
@@ -0,0 +1,27 @@
+From ea7bfd81921827d334c2a23bd11ef0e4e2abafd2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Sat, 9 Nov 2019 08:13:50 +0000
+Subject: [PATCH 616/660] net: sfp: fix sfp_bus_put() kernel documentation
+
+The kbuild test robot found a problem with htmldocs with the recent
+change to the SFP interfaces.  Fix the kernel documentation for
+sfp_bus_put() which was missing an '@' before the argument name
+description.
+
+Fixes: 727b3668b730 ("net: sfp: rework upstream interface")
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp-bus.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/phy/sfp-bus.c
++++ b/drivers/net/phy/sfp-bus.c
+@@ -330,7 +330,7 @@ static void sfp_bus_release(struct kref
+ /**
+  * sfp_bus_put() - put a reference on the &struct sfp_bus
+- * bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
++ * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
+  *
+  * Put a reference on the &struct sfp_bus and free the underlying structure
+  * if this was the last reference.
diff --git a/target/linux/generic/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch b/target/linux/generic/backport-5.4/719-v5.5-net-sfp-fix-sfp_bus_add_upstream-warning.patch
new file mode 100644 (file)
index 0000000..9528049
--- /dev/null
@@ -0,0 +1,27 @@
+From f76d84cd85f8bd3f083495f7ca723822cba8abc9 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Mon, 11 Nov 2019 10:23:35 +0000
+Subject: [PATCH 617/660] net: sfp: fix sfp_bus_add_upstream() warning
+
+When building with SFP disabled, the stub for sfp_bus_add_upstream()
+missed "inline".  Add it.
+
+Fixes: 727b3668b730 ("net: sfp: rework upstream interface")
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ include/linux/sfp.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -563,8 +563,8 @@ static inline struct sfp_bus *sfp_bus_fi
+       return NULL;
+ }
+-static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
+-                              const struct sfp_upstream_ops *ops)
++static inline int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
++                                     const struct sfp_upstream_ops *ops)
+ {
+       return 0;
+ }
diff --git a/target/linux/generic/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch b/target/linux/generic/backport-5.4/720-v5.5-net-sfp-move-sfp-sub-state-machines-into-separate-fu.patch
new file mode 100644 (file)
index 0000000..2f90b00
--- /dev/null
@@ -0,0 +1,124 @@
+From b9d6ed5cdb67533feda7f221eb06f2f9f1ff5047 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 19:33:58 +0100
+Subject: [PATCH 618/660] net: sfp: move sfp sub-state machines into separate
+ functions
+
+Move the SFP sub-state machines out of the main state machine function,
+in preparation for it doing a bit more with the device state.  By doing
+so, we ensure that our debug after the main state machine is always
+printed.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 74 +++++++++++++++++++++++++------------------
+ 1 file changed, 43 insertions(+), 31 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1479,19 +1479,34 @@ static void sfp_sm_mod_remove(struct sfp
+       dev_info(sfp->dev, "module removed\n");
+ }
+-static void sfp_sm_event(struct sfp *sfp, unsigned int event)
++/* This state machine tracks the netdev up/down state */
++static void sfp_sm_device(struct sfp *sfp, unsigned int event)
+ {
+-      mutex_lock(&sfp->sm_mutex);
++      switch (sfp->sm_dev_state) {
++      default:
++              if (event == SFP_E_DEV_UP)
++                      sfp->sm_dev_state = SFP_DEV_UP;
++              break;
+-      dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
+-              mod_state_to_str(sfp->sm_mod_state),
+-              dev_state_to_str(sfp->sm_dev_state),
+-              sm_state_to_str(sfp->sm_state),
+-              event_to_str(event));
++      case SFP_DEV_UP:
++              if (event == SFP_E_DEV_DOWN) {
++                      /* If the module has a PHY, avoid raising TX disable
++                       * as this resets the PHY. Otherwise, raise it to
++                       * turn the laser off.
++                       */
++                      if (!sfp->mod_phy)
++                              sfp_module_tx_disable(sfp);
++                      sfp->sm_dev_state = SFP_DEV_DOWN;
++              }
++              break;
++      }
++}
+-      /* This state machine tracks the insert/remove state of
+-       * the module, and handles probing the on-board EEPROM.
+-       */
++/* This state machine tracks the insert/remove state of
++ * the module, and handles probing the on-board EEPROM.
++ */
++static void sfp_sm_module(struct sfp *sfp, unsigned int event)
++{
+       switch (sfp->sm_mod_state) {
+       default:
+               if (event == SFP_E_INSERT && sfp->attached) {
+@@ -1531,27 +1546,10 @@ static void sfp_sm_event(struct sfp *sfp
+               }
+               break;
+       }
++}
+-      /* This state machine tracks the netdev up/down state */
+-      switch (sfp->sm_dev_state) {
+-      default:
+-              if (event == SFP_E_DEV_UP)
+-                      sfp->sm_dev_state = SFP_DEV_UP;
+-              break;
+-
+-      case SFP_DEV_UP:
+-              if (event == SFP_E_DEV_DOWN) {
+-                      /* If the module has a PHY, avoid raising TX disable
+-                       * as this resets the PHY. Otherwise, raise it to
+-                       * turn the laser off.
+-                       */
+-                      if (!sfp->mod_phy)
+-                              sfp_module_tx_disable(sfp);
+-                      sfp->sm_dev_state = SFP_DEV_DOWN;
+-              }
+-              break;
+-      }
+-
++static void sfp_sm_main(struct sfp *sfp, unsigned int event)
++{
+       /* Some events are global */
+       if (sfp->sm_state != SFP_S_DOWN &&
+           (sfp->sm_mod_state != SFP_MOD_PRESENT ||
+@@ -1562,7 +1560,6 @@ static void sfp_sm_event(struct sfp *sfp
+               if (sfp->mod_phy)
+                       sfp_sm_phy_detach(sfp);
+               sfp_sm_next(sfp, SFP_S_DOWN, 0);
+-              mutex_unlock(&sfp->sm_mutex);
+               return;
+       }
+@@ -1617,6 +1614,21 @@ static void sfp_sm_event(struct sfp *sfp
+       case SFP_S_TX_DISABLE:
+               break;
+       }
++}
++
++static void sfp_sm_event(struct sfp *sfp, unsigned int event)
++{
++      mutex_lock(&sfp->sm_mutex);
++
++      dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
++              mod_state_to_str(sfp->sm_mod_state),
++              dev_state_to_str(sfp->sm_dev_state),
++              sm_state_to_str(sfp->sm_state),
++              event_to_str(event));
++
++      sfp_sm_module(sfp, event);
++      sfp_sm_device(sfp, event);
++      sfp_sm_main(sfp, event);
+       dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
+               mod_state_to_str(sfp->sm_mod_state),
diff --git a/target/linux/generic/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch b/target/linux/generic/backport-5.4/721-v5.5-net-sfp-move-tx-disable-on-device-down-to-main-state.patch
new file mode 100644 (file)
index 0000000..5b3caaf
--- /dev/null
@@ -0,0 +1,41 @@
+From 7e89b737c97a9e7a81dd1584000bc136b92f12fd Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 22:14:47 +0100
+Subject: [PATCH 619/660] net: sfp: move tx disable on device down to main
+ state machine
+
+Move the tx disable assertion on device down to the main state
+machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 10 ++--------
+ 1 file changed, 2 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1489,15 +1489,8 @@ static void sfp_sm_device(struct sfp *sf
+               break;
+       case SFP_DEV_UP:
+-              if (event == SFP_E_DEV_DOWN) {
+-                      /* If the module has a PHY, avoid raising TX disable
+-                       * as this resets the PHY. Otherwise, raise it to
+-                       * turn the laser off.
+-                       */
+-                      if (!sfp->mod_phy)
+-                              sfp_module_tx_disable(sfp);
++              if (event == SFP_E_DEV_DOWN)
+                       sfp->sm_dev_state = SFP_DEV_DOWN;
+-              }
+               break;
+       }
+ }
+@@ -1559,6 +1552,7 @@ static void sfp_sm_main(struct sfp *sfp,
+                       sfp_sm_link_down(sfp);
+               if (sfp->mod_phy)
+                       sfp_sm_phy_detach(sfp);
++              sfp_module_tx_disable(sfp);
+               sfp_sm_next(sfp, SFP_S_DOWN, 0);
+               return;
+       }
diff --git a/target/linux/generic/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch b/target/linux/generic/backport-5.4/722-v5.5-net-sfp-rename-sfp_sm_ins_next-as-sfp_sm_mod_next.patch
new file mode 100644 (file)
index 0000000..ed84e76
--- /dev/null
@@ -0,0 +1,71 @@
+From f2a1ccfc4ad4f97c98c3cc18eb32992151ce089a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 22:27:21 +0100
+Subject: [PATCH 620/660] net: sfp: rename sfp_sm_ins_next() as
+ sfp_sm_mod_next()
+
+sfp_sm_ins_next() modifies the module state machine.  Change it's name
+to reflect this.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1180,7 +1180,7 @@ static void sfp_sm_next(struct sfp *sfp,
+       sfp_sm_set_timer(sfp, timeout);
+ }
+-static void sfp_sm_ins_next(struct sfp *sfp, unsigned int state,
++static void sfp_sm_mod_next(struct sfp *sfp, unsigned int state,
+                           unsigned int timeout)
+ {
+       sfp->sm_mod_state = state;
+@@ -1504,22 +1504,22 @@ static void sfp_sm_module(struct sfp *sf
+       default:
+               if (event == SFP_E_INSERT && sfp->attached) {
+                       sfp_module_tx_disable(sfp);
+-                      sfp_sm_ins_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
++                      sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
+               }
+               break;
+       case SFP_MOD_PROBE:
+               if (event == SFP_E_REMOVE) {
+-                      sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0);
++                      sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+               } else if (event == SFP_E_TIMEOUT) {
+                       int val = sfp_sm_mod_probe(sfp);
+                       if (val == 0)
+-                              sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
++                              sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
+                       else if (val > 0)
+-                              sfp_sm_ins_next(sfp, SFP_MOD_HPOWER, val);
++                              sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val);
+                       else if (val != -EAGAIN)
+-                              sfp_sm_ins_next(sfp, SFP_MOD_ERROR, 0);
++                              sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+                       else
+                               sfp_sm_set_timer(sfp, T_PROBE_RETRY);
+               }
+@@ -1527,7 +1527,7 @@ static void sfp_sm_module(struct sfp *sf
+       case SFP_MOD_HPOWER:
+               if (event == SFP_E_TIMEOUT) {
+-                      sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
++                      sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
+                       break;
+               }
+               /* fallthrough */
+@@ -1535,7 +1535,7 @@ static void sfp_sm_module(struct sfp *sf
+       case SFP_MOD_ERROR:
+               if (event == SFP_E_REMOVE) {
+                       sfp_sm_mod_remove(sfp);
+-                      sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0);
++                      sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+               }
+               break;
+       }
diff --git a/target/linux/generic/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch b/target/linux/generic/backport-5.4/723-v5.5-net-sfp-handle-module-remove-outside-state-machine.patch
new file mode 100644 (file)
index 0000000..542aeae
--- /dev/null
@@ -0,0 +1,53 @@
+From d2591ea5520e2ee8fa557f96bb64c23cafac4b20 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 15 Oct 2019 10:33:13 +0100
+Subject: [PATCH 621/660] net: sfp: handle module remove outside state machine
+
+Removing a module resets the module state machine back to its initial
+state.  Rather than explicitly handling this in every state, handle it
+early on outside of the state machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1500,6 +1500,14 @@ static void sfp_sm_device(struct sfp *sf
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
++      /* Handle remove event globally, it resets this state machine */
++      if (event == SFP_E_REMOVE) {
++              if (sfp->sm_mod_state > SFP_MOD_PROBE)
++                      sfp_sm_mod_remove(sfp);
++              sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++              return;
++      }
++
+       switch (sfp->sm_mod_state) {
+       default:
+               if (event == SFP_E_INSERT && sfp->attached) {
+@@ -1509,9 +1517,7 @@ static void sfp_sm_module(struct sfp *sf
+               break;
+       case SFP_MOD_PROBE:
+-              if (event == SFP_E_REMOVE) {
+-                      sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+-              } else if (event == SFP_E_TIMEOUT) {
++              if (event == SFP_E_TIMEOUT) {
+                       int val = sfp_sm_mod_probe(sfp);
+                       if (val == 0)
+@@ -1533,10 +1539,6 @@ static void sfp_sm_module(struct sfp *sf
+               /* fallthrough */
+       case SFP_MOD_PRESENT:
+       case SFP_MOD_ERROR:
+-              if (event == SFP_E_REMOVE) {
+-                      sfp_sm_mod_remove(sfp);
+-                      sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+-              }
+               break;
+       }
+ }
diff --git a/target/linux/generic/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch b/target/linux/generic/backport-5.4/724-v5.5-net-sfp-rename-T_PROBE_WAIT-to-T_SERIAL.patch
new file mode 100644 (file)
index 0000000..e0c35fe
--- /dev/null
@@ -0,0 +1,51 @@
+From 615090acb3c0b41691f3a03522ea38350387c0e4 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 15 Oct 2019 10:54:15 +0100
+Subject: [PATCH 622/660] net: sfp: rename T_PROBE_WAIT to T_SERIAL
+
+SFF-8472 rev 12.2 defines the time for the serial bus to become ready
+using t_serial.  Use this as our identifier for this timeout to make
+it clear what we are referring to.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -147,11 +147,10 @@ static const enum gpiod_flags gpio_flags
+  * the same length on the PCB, which means it's possible for MOD DEF 0 to
+  * connect before the I2C bus on MOD DEF 1/2.
+  *
+- * The SFP MSA specifies 300ms as t_init (the time taken for TX_FAULT to
+- * be deasserted) but makes no mention of the earliest time before we can
+- * access the I2C EEPROM.  However, Avago modules require 300ms.
++ * The SFF-8472 specifies t_serial ("Time from power on until module is
++ * ready for data transmission over the two wire serial bus.") as 300ms.
+  */
+-#define T_PROBE_INIT  msecs_to_jiffies(300)
++#define T_SERIAL      msecs_to_jiffies(300)
+ #define T_HPOWER_LEVEL        msecs_to_jiffies(300)
+ #define T_PROBE_RETRY msecs_to_jiffies(100)
+@@ -1495,8 +1494,8 @@ static void sfp_sm_device(struct sfp *sf
+       }
+ }
+-/* This state machine tracks the insert/remove state of
+- * the module, and handles probing the on-board EEPROM.
++/* This state machine tracks the insert/remove state of the module, probes
++ * the on-board EEPROM, and sets up the power level.
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
+@@ -1512,7 +1511,7 @@ static void sfp_sm_module(struct sfp *sf
+       default:
+               if (event == SFP_E_INSERT && sfp->attached) {
+                       sfp_module_tx_disable(sfp);
+-                      sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
++                      sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+               }
+               break;
diff --git a/target/linux/generic/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch b/target/linux/generic/backport-5.4/725-v5.5-net-sfp-parse-SFP-power-requirement-earlier.patch
new file mode 100644 (file)
index 0000000..0b358f8
--- /dev/null
@@ -0,0 +1,115 @@
+From d4b8746219e8c0361e5ed6e440ab3a8a600d1f76 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 11 Oct 2019 17:24:40 +0100
+Subject: [PATCH 623/660] net: sfp: parse SFP power requirement earlier
+
+Parse the SFP power requirement earlier, in preparation for moving the
+power level setup code.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -196,6 +196,8 @@ struct sfp {
+       unsigned int sm_retries;
+       struct sfp_eeprom_id id;
++      unsigned int module_power_mW;
++
+ #if IS_ENABLED(CONFIG_HWMON)
+       struct sfp_diag diag;
+       struct device *hwmon_dev;
+@@ -1309,17 +1311,14 @@ static void sfp_sm_mod_init(struct sfp *
+               sfp_sm_probe_phy(sfp);
+ }
+-static int sfp_sm_mod_hpower(struct sfp *sfp)
++static int sfp_module_parse_power(struct sfp *sfp)
+ {
+-      u32 power;
+-      u8 val;
+-      int err;
++      u32 power_mW = 1000;
+-      power = 1000;
+       if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
+-              power = 1500;
++              power_mW = 1500;
+       if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
+-              power = 2000;
++              power_mW = 2000;
+       if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE &&
+           (sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) !=
+@@ -1328,23 +1327,33 @@ static int sfp_sm_mod_hpower(struct sfp
+                * or requires an address change sequence, so assume that
+                * the module powers up in the indicated power mode.
+                */
+-              if (power > sfp->max_power_mW) {
++              if (power_mW > sfp->max_power_mW) {
+                       dev_err(sfp->dev,
+                               "Host does not support %u.%uW modules\n",
+-                              power / 1000, (power / 100) % 10);
++                              power_mW / 1000, (power_mW / 100) % 10);
+                       return -EINVAL;
+               }
+               return 0;
+       }
+-      if (power > sfp->max_power_mW) {
++      if (power_mW > sfp->max_power_mW) {
+               dev_warn(sfp->dev,
+                        "Host does not support %u.%uW modules, module left in power mode 1\n",
+-                       power / 1000, (power / 100) % 10);
++                       power_mW / 1000, (power_mW / 100) % 10);
+               return 0;
+       }
+-      if (power <= 1000)
++      sfp->module_power_mW = power_mW;
++
++      return 0;
++}
++
++static int sfp_sm_mod_hpower(struct sfp *sfp)
++{
++      u8 val;
++      int err;
++
++      if (sfp->module_power_mW <= 1000)
+               return 0;
+       err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
+@@ -1364,7 +1373,8 @@ static int sfp_sm_mod_hpower(struct sfp
+       }
+       dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
+-               power / 1000, (power / 100) % 10);
++               sfp->module_power_mW / 1000,
++               (sfp->module_power_mW / 100) % 10);
+       return T_HPOWER_LEVEL;
+ err:
+@@ -1451,6 +1461,11 @@ static int sfp_sm_mod_probe(struct sfp *
+               dev_warn(sfp->dev,
+                        "module address swap to access page 0xA2 is not supported.\n");
++      /* Parse the module power requirement */
++      ret = sfp_module_parse_power(sfp);
++      if (ret < 0)
++              return ret;
++
+       ret = sfp_hwmon_insert(sfp);
+       if (ret < 0)
+               return ret;
+@@ -1474,6 +1489,7 @@ static void sfp_sm_mod_remove(struct sfp
+       sfp_module_tx_disable(sfp);
+       memset(&sfp->id, 0, sizeof(sfp->id));
++      sfp->module_power_mW = 0;
+       dev_info(sfp->dev, "module removed\n");
+ }
diff --git a/target/linux/generic/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch b/target/linux/generic/backport-5.4/726-v5.5-net-sfp-avoid-power-switch-on-address-change-modules.patch
new file mode 100644 (file)
index 0000000..2ddd4c4
--- /dev/null
@@ -0,0 +1,65 @@
+From dca678b8838945572cf50584cb33a7199c1fd397 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 17 Oct 2019 00:24:18 +0100
+Subject: [PATCH 624/660] net: sfp: avoid power switch on address-change
+ modules
+
+If the module indicates that it requires an address change sequence to
+switch between address 0x50 and 0x51, which we don't support, we can't
+write to the register that controls the power mode to switch to high
+power mode.  Warn the user that the module may not be functional in
+this case, and don't try to change the power mode.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 31 ++++++++++++++++++++-----------
+ 1 file changed, 20 insertions(+), 11 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1320,25 +1320,34 @@ static int sfp_module_parse_power(struct
+       if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
+               power_mW = 2000;
+-      if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE &&
+-          (sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) !=
+-          SFP_DIAGMON_DDM) {
+-              /* The module appears not to implement bus address 0xa2,
+-               * or requires an address change sequence, so assume that
+-               * the module powers up in the indicated power mode.
+-               */
+-              if (power_mW > sfp->max_power_mW) {
++      if (power_mW > sfp->max_power_mW) {
++              /* Module power specification exceeds the allowed maximum. */
++              if (sfp->id.ext.sff8472_compliance ==
++                      SFP_SFF8472_COMPLIANCE_NONE &&
++                  !(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) {
++                      /* The module appears not to implement bus address
++                       * 0xa2, so assume that the module powers up in the
++                       * indicated mode.
++                       */
+                       dev_err(sfp->dev,
+                               "Host does not support %u.%uW modules\n",
+                               power_mW / 1000, (power_mW / 100) % 10);
+                       return -EINVAL;
++              } else {
++                      dev_warn(sfp->dev,
++                               "Host does not support %u.%uW modules, module left in power mode 1\n",
++                               power_mW / 1000, (power_mW / 100) % 10);
++                      return 0;
+               }
+-              return 0;
+       }
+-      if (power_mW > sfp->max_power_mW) {
++      /* If the module requires a higher power mode, but also requires
++       * an address change sequence, warn the user that the module may
++       * not be functional.
++       */
++      if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE && power_mW > 1000) {
+               dev_warn(sfp->dev,
+-                       "Host does not support %u.%uW modules, module left in power mode 1\n",
++                       "Address Change Sequence not supported but module requies %u.%uW, module may not be functional\n",
+                        power_mW / 1000, (power_mW / 100) % 10);
+               return 0;
+       }
diff --git a/target/linux/generic/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch b/target/linux/generic/backport-5.4/727-v5.5-net-sfp-control-TX_DISABLE-and-phy-only-from-main-st.patch
new file mode 100644 (file)
index 0000000..0eac6ab
--- /dev/null
@@ -0,0 +1,52 @@
+From df5c4d93c5a59cba0f7479a4cd4e22b50726ce88 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Thu, 17 Oct 2019 11:12:42 +0100
+Subject: [PATCH 625/660] net: sfp: control TX_DISABLE and phy only from main
+ state machine
+
+We initialise TX_DISABLE when the sfp cage is probed, and then
+maintain its state in the main state machine.  However, the module
+state machine:
+- negates it when detecting a newly inserted module when it's already
+  guaranteed to be negated.
+- negates it when the module is removed, but the main state machine
+  will do this anyway.
+
+Make TX_DISABLE entirely controlled by the main state machine.
+
+The main state machine also probes the module for a PHY, and removes
+the PHY when the the module is removed.  Hence, removing the PHY in
+sfp_sm_module_remove() is also redundant, and is a left-over from
+when we tried to probe for the PHY from the module state machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 9 +--------
+ 1 file changed, 1 insertion(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1492,11 +1492,6 @@ static void sfp_sm_mod_remove(struct sfp
+       sfp_hwmon_remove(sfp);
+-      if (sfp->mod_phy)
+-              sfp_sm_phy_detach(sfp);
+-
+-      sfp_module_tx_disable(sfp);
+-
+       memset(&sfp->id, 0, sizeof(sfp->id));
+       sfp->module_power_mW = 0;
+@@ -1534,10 +1529,8 @@ static void sfp_sm_module(struct sfp *sf
+       switch (sfp->sm_mod_state) {
+       default:
+-              if (event == SFP_E_INSERT && sfp->attached) {
+-                      sfp_module_tx_disable(sfp);
++              if (event == SFP_E_INSERT && sfp->attached)
+                       sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+-              }
+               break;
+       case SFP_MOD_PROBE:
diff --git a/target/linux/generic/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch b/target/linux/generic/backport-5.4/728-v5.5-net-sfp-split-the-PHY-probe-from-sfp_sm_mod_init.patch
new file mode 100644 (file)
index 0000000..7830b92
--- /dev/null
@@ -0,0 +1,53 @@
+From 5ed0bd49b2d3ac4439c2d7f44e5a82b7cf6f409a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 10:09:02 +0100
+Subject: [PATCH 626/660] net: sfp: split the PHY probe from sfp_sm_mod_init()
+
+Move the PHY probe into a separate function, splitting it from
+sfp_sm_mod_init().  This will allow us to eliminate the 50ms mdelay()
+inside the state machine.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 21 +++++++++++++--------
+ 1 file changed, 13 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1288,14 +1288,10 @@ static void sfp_sm_fault(struct sfp *sfp
+ static void sfp_sm_mod_init(struct sfp *sfp)
+ {
+       sfp_module_tx_enable(sfp);
++}
+-      /* Wait t_init before indicating that the link is up, provided the
+-       * current state indicates no TX_FAULT.  If TX_FAULT clears before
+-       * this time, that's fine too.
+-       */
+-      sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
+-      sfp->sm_retries = 5;
+-
++static void sfp_sm_probe_for_phy(struct sfp *sfp)
++{
+       /* Setting the serdes link mode is guesswork: there's no
+        * field in the EEPROM which indicates what mode should
+        * be used.
+@@ -1580,8 +1576,17 @@ static void sfp_sm_main(struct sfp *sfp,
+       switch (sfp->sm_state) {
+       case SFP_S_DOWN:
+               if (sfp->sm_mod_state == SFP_MOD_PRESENT &&
+-                  sfp->sm_dev_state == SFP_DEV_UP)
++                  sfp->sm_dev_state == SFP_DEV_UP) {
+                       sfp_sm_mod_init(sfp);
++                      sfp_sm_probe_for_phy(sfp);
++
++                      /* Wait t_init before indicating that the link is up,
++                       * provided the current state indicates no TX_FAULT. If
++                       * TX_FAULT clears before this time, that's fine too.
++                       */
++                      sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
++                      sfp->sm_retries = 5;
++              }
+               break;
+       case SFP_S_INIT:
diff --git a/target/linux/generic/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch b/target/linux/generic/backport-5.4/729-v5.5-net-sfp-eliminate-mdelay-from-PHY-probe.patch
new file mode 100644 (file)
index 0000000..5dc92bd
--- /dev/null
@@ -0,0 +1,130 @@
+From 0fe72afaa31f98ebd71bd6683fc47021105d0157 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 10:21:46 +0100
+Subject: [PATCH 627/660] net: sfp: eliminate mdelay() from PHY probe
+
+Rather than using mdelay() to wait before probing the PHY (which holds
+several locks, including the rtnl lock), add an extra wait state to
+the state machine to introduce the 50ms delay without holding any
+locks.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 52 +++++++++++++++++++++++++++++++++----------
+ 1 file changed, 40 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -52,6 +52,7 @@ enum {
+       SFP_DEV_UP,
+       SFP_S_DOWN = 0,
++      SFP_S_WAIT,
+       SFP_S_INIT,
+       SFP_S_WAIT_LOS,
+       SFP_S_LINK_UP,
+@@ -108,6 +109,7 @@ static const char *event_to_str(unsigned
+ static const char * const sm_state_strings[] = {
+       [SFP_S_DOWN] = "down",
++      [SFP_S_WAIT] = "wait",
+       [SFP_S_INIT] = "init",
+       [SFP_S_WAIT_LOS] = "wait_los",
+       [SFP_S_LINK_UP] = "link_up",
+@@ -139,6 +141,7 @@ static const enum gpiod_flags gpio_flags
+       GPIOD_ASIS,
+ };
++#define T_WAIT                msecs_to_jiffies(50)
+ #define T_INIT_JIFFIES        msecs_to_jiffies(300)
+ #define T_RESET_US    10
+ #define T_FAULT_RECOVER       msecs_to_jiffies(1000)
+@@ -159,9 +162,6 @@ static const enum gpiod_flags gpio_flags
+  */
+ #define SFP_PHY_ADDR  22
+-/* Give this long for the PHY to reset. */
+-#define T_PHY_RESET_MS        50
+-
+ struct sff_data {
+       unsigned int gpios;
+       bool (*module_supported)(const struct sfp_eeprom_id *id);
+@@ -1202,8 +1202,6 @@ static void sfp_sm_probe_phy(struct sfp
+       struct phy_device *phy;
+       int err;
+-      msleep(T_PHY_RESET_MS);
+-
+       phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR);
+       if (phy == ERR_PTR(-ENODEV)) {
+               dev_info(sfp->dev, "no PHY detected\n");
+@@ -1558,6 +1556,8 @@ static void sfp_sm_module(struct sfp *sf
+ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
+ {
++      unsigned long timeout;
++
+       /* Some events are global */
+       if (sfp->sm_state != SFP_S_DOWN &&
+           (sfp->sm_mod_state != SFP_MOD_PRESENT ||
+@@ -1575,17 +1575,45 @@ static void sfp_sm_main(struct sfp *sfp,
+       /* The main state machine */
+       switch (sfp->sm_state) {
+       case SFP_S_DOWN:
+-              if (sfp->sm_mod_state == SFP_MOD_PRESENT &&
+-                  sfp->sm_dev_state == SFP_DEV_UP) {
+-                      sfp_sm_mod_init(sfp);
+-                      sfp_sm_probe_for_phy(sfp);
++              if (sfp->sm_mod_state != SFP_MOD_PRESENT ||
++                  sfp->sm_dev_state != SFP_DEV_UP)
++                      break;
++
++              sfp_sm_mod_init(sfp);
++
++              /* Initialise the fault clearance retries */
++              sfp->sm_retries = 5;
++
++              /* We need to check the TX_FAULT state, which is not defined
++               * while TX_DISABLE is asserted. The earliest we want to do
++               * anything (such as probe for a PHY) is 50ms.
++               */
++              sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
++              break;
++
++      case SFP_S_WAIT:
++              if (event != SFP_E_TIMEOUT)
++                      break;
++
++              sfp_sm_probe_for_phy(sfp);
++              if (sfp->state & SFP_F_TX_FAULT) {
+                       /* Wait t_init before indicating that the link is up,
+                        * provided the current state indicates no TX_FAULT. If
+                        * TX_FAULT clears before this time, that's fine too.
+                        */
+-                      sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
+-                      sfp->sm_retries = 5;
++                      timeout = T_INIT_JIFFIES;
++                      if (timeout > T_WAIT)
++                              timeout -= T_WAIT;
++                      else
++                              timeout = 1;
++
++                      sfp_sm_next(sfp, SFP_S_INIT, timeout);
++              } else {
++                      /* TX_FAULT is not asserted, assume the module has
++                       * finished initialising.
++                       */
++                      goto init_done;
+               }
+               break;
+@@ -1593,7 +1621,7 @@ static void sfp_sm_main(struct sfp *sfp,
+               if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
+                       sfp_sm_fault(sfp, true);
+               else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
+-                      sfp_sm_link_check_los(sfp);
++      init_done:      sfp_sm_link_check_los(sfp);
+               break;
+       case SFP_S_WAIT_LOS:
diff --git a/target/linux/generic/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch b/target/linux/generic/backport-5.4/730-v5.5-net-sfp-allow-fault-processing-to-transition-to-othe.patch
new file mode 100644 (file)
index 0000000..6e34e6c
--- /dev/null
@@ -0,0 +1,69 @@
+From 2aa424ee7fbe43e2cd24e28c2f6388c4e1796bd2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 09:58:33 +0100
+Subject: [PATCH 628/660] net: sfp: allow fault processing to transition to
+ other states
+
+Add the next state to sfp_sm_fault() so that it can branch to other
+states. This will be necessary to improve the initialisation path.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -1269,7 +1269,7 @@ static bool sfp_los_event_inactive(struc
+               event == SFP_E_LOS_LOW);
+ }
+-static void sfp_sm_fault(struct sfp *sfp, bool warn)
++static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
+ {
+       if (sfp->sm_retries && !--sfp->sm_retries) {
+               dev_err(sfp->dev,
+@@ -1279,7 +1279,7 @@ static void sfp_sm_fault(struct sfp *sfp
+               if (warn)
+                       dev_err(sfp->dev, "module transmit fault indicated\n");
+-              sfp_sm_next(sfp, SFP_S_TX_FAULT, T_FAULT_RECOVER);
++              sfp_sm_next(sfp, next_state, T_FAULT_RECOVER);
+       }
+ }
+@@ -1619,14 +1619,14 @@ static void sfp_sm_main(struct sfp *sfp,
+       case SFP_S_INIT:
+               if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
+-                      sfp_sm_fault(sfp, true);
++                      sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+               else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
+       init_done:      sfp_sm_link_check_los(sfp);
+               break;
+       case SFP_S_WAIT_LOS:
+               if (event == SFP_E_TX_FAULT)
+-                      sfp_sm_fault(sfp, true);
++                      sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+               else if (sfp_los_event_inactive(sfp, event))
+                       sfp_sm_link_up(sfp);
+               break;
+@@ -1634,7 +1634,7 @@ static void sfp_sm_main(struct sfp *sfp,
+       case SFP_S_LINK_UP:
+               if (event == SFP_E_TX_FAULT) {
+                       sfp_sm_link_down(sfp);
+-                      sfp_sm_fault(sfp, true);
++                      sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+               } else if (sfp_los_event_active(sfp, event)) {
+                       sfp_sm_link_down(sfp);
+                       sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0);
+@@ -1650,7 +1650,7 @@ static void sfp_sm_main(struct sfp *sfp,
+       case SFP_S_REINIT:
+               if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
+-                      sfp_sm_fault(sfp, false);
++                      sfp_sm_fault(sfp, SFP_S_TX_FAULT, false);
+               } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
+                       dev_info(sfp->dev, "module transmit fault recovered\n");
+                       sfp_sm_link_check_los(sfp);
diff --git a/target/linux/generic/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch b/target/linux/generic/backport-5.4/731-v5.5-net-sfp-ensure-TX_FAULT-has-deasserted-before-probin.patch
new file mode 100644 (file)
index 0000000..03415fb
--- /dev/null
@@ -0,0 +1,80 @@
+From 38b62a12231be4b86fc5ca5477579d29831c02a5 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 18 Oct 2019 10:31:07 +0100
+Subject: [PATCH 629/660] net: sfp: ensure TX_FAULT has deasserted before
+ probing the PHY
+
+TX_FAULT should be deasserted to indicate that the module has completed
+its initialisation.  This may include the on-board PHY, so wait until
+the module has deasserted TX_FAULT before probing the PHY.
+
+This means that we need an extra state to handle a TX_FAULT that
+remains set for longer than t_init, since using the existing handling
+state would bypass the PHY probe.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 31 +++++++++++++++++++++++++------
+ 1 file changed, 25 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -54,6 +54,7 @@ enum {
+       SFP_S_DOWN = 0,
+       SFP_S_WAIT,
+       SFP_S_INIT,
++      SFP_S_INIT_TX_FAULT,
+       SFP_S_WAIT_LOS,
+       SFP_S_LINK_UP,
+       SFP_S_TX_FAULT,
+@@ -111,6 +112,7 @@ static const char * const sm_state_strin
+       [SFP_S_DOWN] = "down",
+       [SFP_S_WAIT] = "wait",
+       [SFP_S_INIT] = "init",
++      [SFP_S_INIT_TX_FAULT] = "init_tx_fault",
+       [SFP_S_WAIT_LOS] = "wait_los",
+       [SFP_S_LINK_UP] = "link_up",
+       [SFP_S_TX_FAULT] = "tx_fault",
+@@ -1595,8 +1597,6 @@ static void sfp_sm_main(struct sfp *sfp,
+               if (event != SFP_E_TIMEOUT)
+                       break;
+-              sfp_sm_probe_for_phy(sfp);
+-
+               if (sfp->state & SFP_F_TX_FAULT) {
+                       /* Wait t_init before indicating that the link is up,
+                        * provided the current state indicates no TX_FAULT. If
+@@ -1618,10 +1618,29 @@ static void sfp_sm_main(struct sfp *sfp,
+               break;
+       case SFP_S_INIT:
+-              if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
+-                      sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
+-              else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
+-      init_done:      sfp_sm_link_check_los(sfp);
++              if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
++                      /* TX_FAULT is still asserted after t_init, so assume
++                       * there is a fault.
++                       */
++                      sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
++                                   sfp->sm_retries == 5);
++              } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
++      init_done:      /* TX_FAULT deasserted or we timed out with TX_FAULT
++                       * clear.  Probe for the PHY and check the LOS state.
++                       */
++                      sfp_sm_probe_for_phy(sfp);
++                      sfp_sm_link_check_los(sfp);
++
++                      /* Reset the fault retry count */
++                      sfp->sm_retries = 5;
++              }
++              break;
++
++      case SFP_S_INIT_TX_FAULT:
++              if (event == SFP_E_TIMEOUT) {
++                      sfp_module_tx_fault_reset(sfp);
++                      sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
++              }
+               break;
+       case SFP_S_WAIT_LOS:
diff --git a/target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch b/target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch
new file mode 100644 (file)
index 0000000..5ee44db
--- /dev/null
@@ -0,0 +1,153 @@
+From ec6036a58f979c66bbd5cd9d0d1c783a98c2c644 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 12:57:40 +0000
+Subject: [PATCH 630/660] net: sfp: track upstream's attachment state in state
+ machine
+
+Track the upstream's attachment state in the state machine rather than
+maintaining a boolean, which ensures that we have a strict order of
+ATTACH followed by an UP event - we can never believe that a newly
+attached upstream will be anything but down.
+
+Rearrange the order of state machines so we run the module state
+machine after the upstream device's state machine, so the module state
+machine can check the current state of the device and take action to
+e.g. reset back to empty state when the upstream is detached.
+
+This is to allow the module detection to run independently of the
+network device becoming available.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -34,6 +34,8 @@ enum {
+       SFP_E_INSERT = 0,
+       SFP_E_REMOVE,
++      SFP_E_DEV_ATTACH,
++      SFP_E_DEV_DETACH,
+       SFP_E_DEV_DOWN,
+       SFP_E_DEV_UP,
+       SFP_E_TX_FAULT,
+@@ -48,7 +50,8 @@ enum {
+       SFP_MOD_PRESENT,
+       SFP_MOD_ERROR,
+-      SFP_DEV_DOWN = 0,
++      SFP_DEV_DETACHED = 0,
++      SFP_DEV_DOWN,
+       SFP_DEV_UP,
+       SFP_S_DOWN = 0,
+@@ -78,6 +81,7 @@ static const char *mod_state_to_str(unsi
+ }
+ static const char * const dev_state_strings[] = {
++      [SFP_DEV_DETACHED] = "detached",
+       [SFP_DEV_DOWN] = "down",
+       [SFP_DEV_UP] = "up",
+ };
+@@ -92,6 +96,8 @@ static const char *dev_state_to_str(unsi
+ static const char * const event_strings[] = {
+       [SFP_E_INSERT] = "insert",
+       [SFP_E_REMOVE] = "remove",
++      [SFP_E_DEV_ATTACH] = "dev_attach",
++      [SFP_E_DEV_DETACH] = "dev_detach",
+       [SFP_E_DEV_DOWN] = "dev_down",
+       [SFP_E_DEV_UP] = "dev_up",
+       [SFP_E_TX_FAULT] = "tx_fault",
+@@ -186,7 +192,6 @@ struct sfp {
+       struct gpio_desc *gpio[GPIO_MAX];
+       int gpio_irq[GPIO_MAX];
+-      bool attached;
+       struct mutex st_mutex;                  /* Protects state */
+       unsigned int state;
+       struct delayed_work poll;
+@@ -1494,17 +1499,26 @@ static void sfp_sm_mod_remove(struct sfp
+       dev_info(sfp->dev, "module removed\n");
+ }
+-/* This state machine tracks the netdev up/down state */
++/* This state machine tracks the upstream's state */
+ static void sfp_sm_device(struct sfp *sfp, unsigned int event)
+ {
+       switch (sfp->sm_dev_state) {
+       default:
+-              if (event == SFP_E_DEV_UP)
++              if (event == SFP_E_DEV_ATTACH)
++                      sfp->sm_dev_state = SFP_DEV_DOWN;
++              break;
++
++      case SFP_DEV_DOWN:
++              if (event == SFP_E_DEV_DETACH)
++                      sfp->sm_dev_state = SFP_DEV_DETACHED;
++              else if (event == SFP_E_DEV_UP)
+                       sfp->sm_dev_state = SFP_DEV_UP;
+               break;
+       case SFP_DEV_UP:
+-              if (event == SFP_E_DEV_DOWN)
++              if (event == SFP_E_DEV_DETACH)
++                      sfp->sm_dev_state = SFP_DEV_DETACHED;
++              else if (event == SFP_E_DEV_DOWN)
+                       sfp->sm_dev_state = SFP_DEV_DOWN;
+               break;
+       }
+@@ -1515,17 +1529,20 @@ static void sfp_sm_device(struct sfp *sf
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
+-      /* Handle remove event globally, it resets this state machine */
+-      if (event == SFP_E_REMOVE) {
++      /* Handle remove event globally, it resets this state machine.
++       * Also deal with upstream detachment.
++       */
++      if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
+               if (sfp->sm_mod_state > SFP_MOD_PROBE)
+                       sfp_sm_mod_remove(sfp);
+-              sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++              if (sfp->sm_mod_state != SFP_MOD_EMPTY)
++                      sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+               return;
+       }
+       switch (sfp->sm_mod_state) {
+       default:
+-              if (event == SFP_E_INSERT && sfp->attached)
++              if (event == SFP_E_INSERT)
+                       sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+               break;
+@@ -1691,8 +1708,8 @@ static void sfp_sm_event(struct sfp *sfp
+               sm_state_to_str(sfp->sm_state),
+               event_to_str(event));
+-      sfp_sm_module(sfp, event);
+       sfp_sm_device(sfp, event);
++      sfp_sm_module(sfp, event);
+       sfp_sm_main(sfp, event);
+       dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
+@@ -1705,15 +1722,14 @@ static void sfp_sm_event(struct sfp *sfp
+ static void sfp_attach(struct sfp *sfp)
+ {
+-      sfp->attached = true;
++      sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
+       if (sfp->state & SFP_F_PRESENT)
+               sfp_sm_event(sfp, SFP_E_INSERT);
+ }
+ static void sfp_detach(struct sfp *sfp)
+ {
+-      sfp->attached = false;
+-      sfp_sm_event(sfp, SFP_E_REMOVE);
++      sfp_sm_event(sfp, SFP_E_DEV_DETACH);
+ }
+ static void sfp_start(struct sfp *sfp)
diff --git a/target/linux/generic/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch b/target/linux/generic/backport-5.4/733-v5.5-net-sfp-split-power-mode-switching-from-probe.patch
new file mode 100644 (file)
index 0000000..06b3cb5
--- /dev/null
@@ -0,0 +1,184 @@
+From fdff863a4ce3677907f64396e34c45025abb6600 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 12:59:36 +0000
+Subject: [PATCH 631/660] net: sfp: split power mode switching from probe
+
+Switch the power mode switching from the probe, so that we don't
+repeatedly re-probe the SFP device if there is a problem accessing
+the registers at I2C address 0x51.
+
+In splitting this out, we can also fix a bug where we leave the module
+in high-power mode when the upstream device is detached but the module
+is still inserted.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 101 ++++++++++++++++++++++++++----------------
+ 1 file changed, 64 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -47,6 +47,7 @@ enum {
+       SFP_MOD_EMPTY = 0,
+       SFP_MOD_PROBE,
+       SFP_MOD_HPOWER,
++      SFP_MOD_WAITPWR,
+       SFP_MOD_PRESENT,
+       SFP_MOD_ERROR,
+@@ -69,6 +70,7 @@ static const char  * const mod_state_str
+       [SFP_MOD_EMPTY] = "empty",
+       [SFP_MOD_PROBE] = "probe",
+       [SFP_MOD_HPOWER] = "hpower",
++      [SFP_MOD_WAITPWR] = "waitpwr",
+       [SFP_MOD_PRESENT] = "present",
+       [SFP_MOD_ERROR] = "error",
+ };
+@@ -1358,37 +1360,34 @@ static int sfp_module_parse_power(struct
+       return 0;
+ }
+-static int sfp_sm_mod_hpower(struct sfp *sfp)
++static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
+ {
+       u8 val;
+       int err;
+-      if (sfp->module_power_mW <= 1000)
+-              return 0;
+-
+       err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
+       if (err != sizeof(val)) {
+               dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err);
+-              err = -EAGAIN;
+-              goto err;
++              return -EAGAIN;
+       }
+-      val |= BIT(0);
++      if (enable)
++              val |= BIT(0);
++      else
++              val &= ~BIT(0);
+       err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
+       if (err != sizeof(val)) {
+               dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err);
+-              err = -EAGAIN;
+-              goto err;
++              return -EAGAIN;
+       }
+-      dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
+-               sfp->module_power_mW / 1000,
+-               (sfp->module_power_mW / 100) % 10);
+-      return T_HPOWER_LEVEL;
++      if (enable)
++              dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
++                       sfp->module_power_mW / 1000,
++                       (sfp->module_power_mW / 100) % 10);
+-err:
+-      return err;
++      return 0;
+ }
+ static int sfp_sm_mod_probe(struct sfp *sfp)
+@@ -1484,7 +1483,7 @@ static int sfp_sm_mod_probe(struct sfp *
+       if (ret < 0)
+               return ret;
+-      return sfp_sm_mod_hpower(sfp);
++      return 0;
+ }
+ static void sfp_sm_mod_remove(struct sfp *sfp)
+@@ -1529,13 +1528,22 @@ static void sfp_sm_device(struct sfp *sf
+  */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
+-      /* Handle remove event globally, it resets this state machine.
+-       * Also deal with upstream detachment.
+-       */
+-      if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
++      int err;
++
++      /* Handle remove event globally, it resets this state machine */
++      if (event == SFP_E_REMOVE) {
+               if (sfp->sm_mod_state > SFP_MOD_PROBE)
+                       sfp_sm_mod_remove(sfp);
+-              if (sfp->sm_mod_state != SFP_MOD_EMPTY)
++              sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++              return;
++      }
++
++      /* Handle device detach globally */
++      if (sfp->sm_dev_state < SFP_DEV_DOWN) {
++              if (sfp->module_power_mW > 1000 &&
++                  sfp->sm_mod_state > SFP_MOD_HPOWER)
++                      sfp_sm_mod_hpower(sfp, false);
++              if (sfp->sm_mod_state > SFP_MOD_EMPTY)
+                       sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+               return;
+       }
+@@ -1547,26 +1555,45 @@ static void sfp_sm_module(struct sfp *sf
+               break;
+       case SFP_MOD_PROBE:
+-              if (event == SFP_E_TIMEOUT) {
+-                      int val = sfp_sm_mod_probe(sfp);
++              if (event != SFP_E_TIMEOUT)
++                      break;
+-                      if (val == 0)
+-                              sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
+-                      else if (val > 0)
+-                              sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val);
+-                      else if (val != -EAGAIN)
+-                              sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
+-                      else
+-                              sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++              err = sfp_sm_mod_probe(sfp);
++              if (err == -EAGAIN) {
++                      sfp_sm_set_timer(sfp, T_PROBE_RETRY);
++                      break;
+               }
+-              break;
++              if (err < 0) {
++                      sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
++                      break;
++              }
++
++              /* If this is a power level 1 module, we are done */
++              if (sfp->module_power_mW <= 1000)
++                      goto insert;
++              sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0);
++              /* fall through */
+       case SFP_MOD_HPOWER:
+-              if (event == SFP_E_TIMEOUT) {
+-                      sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
++              /* Enable high power mode */
++              err = sfp_sm_mod_hpower(sfp, true);
++              if (err == 0)
++                      sfp_sm_mod_next(sfp,